about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--RELEASES.md126
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs31
-rw-r--r--compiler/rustc_ast_passes/messages.ftl4
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs40
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs18
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prelude.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/interface.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/target_checking.rs15
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl11
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs22
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs3
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs16
-rw-r--r--compiler/rustc_expand/messages.ftl29
-rw-r--r--compiler/rustc_expand/src/config.rs3
-rw-r--r--compiler/rustc_expand/src/errors.rs78
-rw-r--r--compiler/rustc_expand/src/expand.rs5
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs45
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs5
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs26
-rw-r--r--compiler/rustc_hir/src/intravisit.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs10
-rw-r--r--compiler/rustc_interface/messages.ftl3
-rw-r--r--compiler/rustc_interface/src/errors.rs17
-rw-r--r--compiler/rustc_interface/src/util.rs8
-rw-r--r--compiler/rustc_lint/messages.ftl73
-rw-r--r--compiler/rustc_lint/src/builtin.rs20
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs84
-rw-r--r--compiler/rustc_lint/src/lints.rs166
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs35
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs51
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs13
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs38
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/parameterized.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs7
-rw-r--r--compiler/rustc_middle/src/query/erase.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs63
-rw-r--r--compiler/rustc_middle/src/ty/context.rs26
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs43
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/dead.rs44
-rw-r--r--compiler/rustc_passes/src/stability.rs7
-rw-r--r--compiler/rustc_public/src/ty.rs12
-rw-r--r--compiler/rustc_public/src/unstable/convert/stable/ty.rs20
-rw-r--r--compiler/rustc_resolve/messages.ftl24
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/errors.rs55
-rw-r--r--compiler/rustc_resolve/src/ident.rs3
-rw-r--r--compiler/rustc_resolve/src/imports.rs6
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs3
-rw-r--r--compiler/rustc_span/src/hygiene.rs30
-rw-r--r--compiler/rustc_span/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs2
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs35
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs2
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs7
-rw-r--r--library/core/src/ffi/va_list.rs29
-rw-r--r--library/core/src/num/bignum.rs37
-rw-r--r--library/coretests/tests/fmt/builders.rs15
-rw-r--r--library/coretests/tests/fmt/mod.rs30
-rw-r--r--library/coretests/tests/fmt/num.rs6
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/coretests/tests/num/bignum.rs19
-rw-r--r--library/coretests/tests/ptr.rs8
-rw-r--r--library/std/src/keyword_docs.rs102
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/sync/nonpoison/condvar.rs9
-rw-r--r--library/std/src/sync/poison/condvar.rs9
-rw-r--r--library/std/src/sys/pal/hermit/time.rs32
-rw-r--r--library/std/src/sys/pal/sgx/time.rs15
-rw-r--r--library/std/src/sys/pal/solid/time.rs9
-rw-r--r--library/std/src/sys/pal/uefi/time.rs27
-rw-r--r--library/std/src/sys/pal/unix/time.rs30
-rw-r--r--library/std/src/sys/pal/unsupported/time.rs15
-rw-r--r--library/std/src/sys/pal/wasip1/time.rs25
-rw-r--r--library/std/src/sys/pal/wasip2/time.rs25
-rw-r--r--library/std/src/sys/pal/windows/time.rs30
-rw-r--r--library/std/src/sys/pal/xous/time.rs15
-rw-r--r--library/std/src/time.rs30
-rw-r--r--src/bootstrap/src/core/sanity.rs2
-rw-r--r--src/doc/rustc/src/SUMMARY.md5
-rw-r--r--src/doc/rustc/src/check-cfg.md2
-rw-r--r--src/doc/rustc/src/platform-support.md10
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-unknown-none.md78
-rw-r--r--src/doc/rustc/src/platform-support/arm-none-eabi.md6
-rw-r--r--src/doc/rustc/src/platform-support/armebv7r-none-eabi.md55
-rw-r--r--src/doc/rustc/src/platform-support/armv4t-none-eabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-none-eabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7a-none-eabi.md70
-rw-r--r--src/doc/rustc/src/platform-support/armv7r-none-eabi.md28
-rw-r--r--src/doc/rustc/src/platform-support/armv8r-none-eabihf.md21
-rw-r--r--src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md5
-rw-r--r--src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md5
-rw-r--r--src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md5
-rw-r--r--src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md5
-rw-r--r--src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md5
-rw-r--r--src/librustdoc/clean/mod.rs35
-rw-r--r--src/librustdoc/clean/types.rs33
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs32
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/compiletest/src/directives.rs9
-rw-r--r--src/tools/compiletest/src/directives/tests.rs8
-rw-r--r--src/tools/compiletest/src/executor.rs11
-rw-r--r--src/tools/compiletest/src/lib.rs37
-rw-r--r--src/tools/tidy/src/deps.rs177
-rw-r--r--src/tools/tidy/src/extdeps.rs12
-rw-r--r--src/tools/tidy/src/fluent_lowercase.rs64
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--src/version2
-rw-r--r--tests/codegen-llvm/c-variadic-lifetime.rs4
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-inline.rs47
-rw-r--r--tests/ui/c-variadic/naked.rs40
-rw-r--r--tests/ui/const-generics/generic_arg_infer/paren_infer.rs (renamed from tests/ui/const-generics/generic_arg_infer/parend_infer.rs)1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr19
-rw-r--r--tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs1
-rw-r--r--tests/ui/explicit-tail-calls/c-variadic.rs14
-rw-r--r--tests/ui/explicit-tail-calls/c-variadic.stderr8
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs2
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr2
-rw-r--r--tests/ui/macros/issue-61053-duplicate-binder.stderr4
162 files changed, 1780 insertions, 1281 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 33abe45ce46..2b65d070d5f 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,129 @@
+Version 1.90 (2025-09-18)
+==========================
+
+<a id="1.90-Language"></a>
+
+Language
+--------
+- [Split up the `unknown_or_malformed_diagnostic_attributes` lint](https://github.com/rust-lang/rust/pull/140717). This lint has been split up into four finer-grained lints, with `unknown_or_malformed_diagnostic_attributes` now being the lint group that contains these lints:
+    1. `unknown_diagnostic_attributes`: unknown to the current compiler
+    2. `misplaced_diagnostic_attributes`: placed on the wrong item
+    3. `malformed_diagnostic_attributes`: malformed attribute syntax or options
+    4. `malformed_diagnostic_format_literals`: malformed format string literal
+- [Allow constants whose final value has references to mutable/external memory, but reject such constants as patterns](https://github.com/rust-lang/rust/pull/140942)
+- [Allow volatile access to non-Rust memory, including address 0](https://github.com/rust-lang/rust/pull/141260)
+
+
+<a id="1.90-Compiler"></a>
+
+Compiler
+--------
+- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
+- [Tier 3 `musl` targets now link dynamically by default](https://github.com/rust-lang/rust/pull/144410). Affected targets:
+    - `mips64-unknown-linux-muslabi64`
+    - `powerpc64-unknown-linux-musl`
+    - `powerpc-unknown-linux-musl`
+    - `powerpc-unknown-linux-muslspe`
+    - `riscv32gc-unknown-linux-musl`
+    - `s390x-unknown-linux-musl`
+    - `thumbv7neon-unknown-linux-musleabihf`
+
+
+<a id="1.90-Platform-Support"></a>
+
+Platform Support
+----------------
+- [Demote `x86_64-apple-darwin` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/145252)
+
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+<a id="1.90-Libraries"></a>
+
+Libraries
+---------
+- [Stabilize `u*::{checked,overflowing,saturating,wrapping}_sub_signed`](https://github.com/rust-lang/rust/issues/126043)
+- [Allow comparisons between `CStr`, `CString`, and `Cow<CStr>`](https://github.com/rust-lang/rust/pull/137268)
+- [Remove some unsized tuple impls since unsized tuples can't be constructed](https://github.com/rust-lang/rust/pull/138340)
+- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
+- [`proc_macro::Ident::new` now supports `$crate`.](https://github.com/rust-lang/rust/pull/141996)
+- [Guarantee the pointer returned from `Thread::into_raw` has at least 8 bytes of alignment](https://github.com/rust-lang/rust/pull/143859)
+
+
+<a id="1.90-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [`u{n}::checked_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.checked_sub_signed)
+- [`u{n}::overflowing_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.overflowing_sub_signed)
+- [`u{n}::saturating_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.saturating_sub_signed)
+- [`u{n}::wrapping_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.wrapping_sub_signed)
+- [`impl Copy for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Copy-for-IntErrorKind)
+- [`impl Hash for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Hash-for-IntErrorKind)
+- [`impl PartialEq<&CStr> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3C%26CStr%3E-for-CStr)
+- [`impl PartialEq<CString> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCString%3E-for-CStr)
+- [`impl PartialEq<Cow<CStr>> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CStr)
+- [`impl PartialEq<&CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3C%26CStr%3E-for-CString)
+- [`impl PartialEq<CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCStr%3E-for-CString)
+- [`impl PartialEq<Cow<CStr>> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CString)
+- [`impl PartialEq<&CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3C%26CStr%3E-for-Cow%3C'_,+CStr%3E)
+- [`impl PartialEq<CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCStr%3E-for-Cow%3C'_,+CStr%3E)
+- [`impl PartialEq<CString> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCString%3E-for-Cow%3C'_,+CStr%3E)
+
+
+These previously stable APIs are now stable in const contexts:
+
+- [`<[T]>::reverse`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.reverse)
+- [`f32::floor`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.floor)
+- [`f32::ceil`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.ceil)
+- [`f32::trunc`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.trunc)
+- [`f32::fract`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.fract)
+- [`f32::round`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round)
+- [`f32::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even)
+- [`f64::floor`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.floor)
+- [`f64::ceil`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.ceil)
+- [`f64::trunc`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.trunc)
+- [`f64::fract`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.fract)
+- [`f64::round`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round)
+- [`f64::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even)
+
+
+<a id="1.90-Cargo"></a>
+
+Cargo
+-----
+- [Add `http.proxy-cainfo` config for proxy certs](https://github.com/rust-lang/cargo/pull/15374/)
+- [Use `gix` for `cargo package`](https://github.com/rust-lang/cargo/pull/15534/)
+- [feat(publish): Stabilize multi-package publishing](https://github.com/rust-lang/cargo/pull/15636/)
+
+<a id="1.90-Rustdoc"></a>
+
+Rustdoc
+-----
+- [Add ways to collapse all impl blocks](https://github.com/rust-lang/rust/pull/141663). Previously the "Summary" button and "-" keyboard shortcut would never collapse `impl` blocks, now they do when shift is held
+- [Display unsafe attributes with `unsafe()` wrappers](https://github.com/rust-lang/rust/pull/143662)
+
+
+<a id="1.90-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
+  See also <https://blog.rust-lang.org/2025/09/01/rust-lld-on-1.90.0-stable/>.
+- [Make `core::iter::Fuse`'s `Default` impl construct `I::default()` internally as promised in the docs instead of always being empty](https://github.com/rust-lang/rust/pull/140985)
+- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
+  This may change program behavior but results in the same behavior as other primitives (e.g., stdout, network sockets).
+  Programs relying on signals to terminate them should update handling of sockets to handle errors on write by exiting.
+- [On Unix `std::env::home_dir` will use the fallback if the `HOME` environment variable is empty](https://github.com/rust-lang/rust/pull/141840)
+- We now [reject unsupported `extern "{abi}"`s consistently in all positions](https://github.com/rust-lang/rust/pull/142134). This primarily affects the use of implementing traits on an `extern "{abi}"` function pointer, like `extern "stdcall" fn()`, on a platform that doesn't support that, like aarch64-unknown-linux-gnu. Direct usage of these unsupported ABI strings by declaring or defining functions was already rejected, so this is only a change for consistency.
+- [const-eval: error when initializing a static writes to that static](https://github.com/rust-lang/rust/pull/143084)
+- [Check that the `proc_macro_derive` macro has correct arguments when applied to the crate root](https://github.com/rust-lang/rust/pull/143607)
+
+
 Version 1.89.0 (2025-08-07)
 ==========================
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index bb559bd8921..53351f91c46 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -5,7 +5,9 @@ use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
-use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, Target, find_attr};
+use rustc_hir::{
+    self as hir, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr,
+};
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
@@ -1117,20 +1119,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
         };
 
+        let span = self.lower_span(i.span);
         let item = hir::ImplItem {
             owner_id: hir_id.expect_owner(),
             ident: self.lower_ident(ident),
             generics,
+            impl_kind: if is_in_trait_impl {
+                ImplItemImplKind::Trait {
+                    defaultness,
+                    trait_item_def_id: self
+                        .resolver
+                        .get_partial_res(i.id)
+                        .and_then(|r| r.expect_full_res().opt_def_id())
+                        .ok_or_else(|| {
+                            self.dcx().span_delayed_bug(
+                                span,
+                                "could not resolve trait item being implemented",
+                            )
+                        }),
+                }
+            } else {
+                ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }
+            },
             kind,
-            vis_span: self.lower_span(i.vis.span),
-            span: self.lower_span(i.span),
-            defaultness,
+            span,
             has_delayed_lints: !self.delayed_lints.is_empty(),
-            trait_item_def_id: self
-                .resolver
-                .get_partial_res(i.id)
-                .map(|r| r.expect_full_res().opt_def_id())
-                .unwrap_or(None),
         };
         self.arena.alloc(item)
     }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 8dcf3e3aa38..e5405a7ad91 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -216,6 +216,10 @@ ast_passes_match_arm_with_no_body =
     .suggestion = add a body after the pattern
 
 ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
+    .suggestion = needs `unsafe` before the extern keyword
+
+ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe
+    .suggestion = needs `unsafe` before the extern keyword
 
 ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
     .help = consider using the `#[path]` attribute to specify filesystem path
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a6ef89b553d..dc221c2fb1a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1131,7 +1131,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                             MISSING_UNSAFE_ON_EXTERN,
                             item.id,
                             item.span,
-                            BuiltinLintDiag::MissingUnsafeOnExtern {
+                            errors::MissingUnsafeOnExternLint {
                                 suggestion: item.span.shrink_to_lo(),
                             },
                         );
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ae805042c54..e09ca5b81c8 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -523,6 +523,13 @@ pub(crate) struct MissingUnsafeOnExtern {
     pub span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(ast_passes_missing_unsafe_on_extern_lint)]
+pub(crate) struct MissingUnsafeOnExternLint {
+    #[suggestion(code = "unsafe ", applicability = "machine-applicable")]
+    pub suggestion: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(ast_passes_fieldless_union)]
 pub(crate) struct FieldlessUnion {
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 0b2c05482bf..4611de44459 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -43,11 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(n) = args else {
@@ -76,11 +72,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -103,11 +95,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -130,11 +118,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -157,11 +141,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -182,11 +162,8 @@ pub(crate) struct NoCoreParser;
 impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
     const PATH: &[Symbol] = &[sym::no_core];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
-    const TYPE: AttributeType = AttributeType::CrateLevel;
 }
 
 pub(crate) struct NoStdParser;
@@ -194,9 +171,6 @@ pub(crate) struct NoStdParser;
 impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
     const PATH: &[Symbol] = &[sym::no_std];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
-    const TYPE: AttributeType = AttributeType::CrateLevel;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 043bc925eac..4ed13d239b9 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -12,15 +12,11 @@
 //! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the
 //! contents of attributes, if an attribute appear multiple times in a list
 //!
-//! By default, attributes are allowed anywhere. When adding an attribute that should only be used
-//! at the crate root, consider setting the `TYPE` in the parser trait to
-//! [`AttributeType::CrateLevel`](rustc_feature::AttributeType::CrateLevel).
-//!
 //! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
 
 use std::marker::PhantomData;
 
-use rustc_feature::{AttributeTemplate, AttributeType, template};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
@@ -89,11 +85,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
     ///
     /// If an attribute has this symbol, the `accept` function will be called on it.
     const ATTRIBUTES: AcceptMapping<Self, S>;
-
     const ALLOWED_TARGETS: AllowedTargets;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// The parser has gotten a chance to accept the attributes on an item,
     /// here it can produce an attribute.
     ///
@@ -135,8 +128,6 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
 }
@@ -183,8 +174,6 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
     )];
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
 
-    const TYPE: AttributeType = T::TYPE;
-
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(self.1?.0)
     }
@@ -269,7 +258,6 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
     const PATH: &[Symbol];
     const ON_DUPLICATE: OnDuplicate<S>;
     const ALLOWED_TARGETS: AllowedTargets;
-    const TYPE: AttributeType = AttributeType::Normal;
 
     /// Create the [`AttributeKind`] given attribute's [`Span`].
     const CREATE: fn(Span) -> AttributeKind;
@@ -289,7 +277,6 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
     const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
     const TEMPLATE: AttributeTemplate = template!(Word);
-    const TYPE: AttributeType = T::TYPE;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         if let Err(span) = args.no_args() {
@@ -323,8 +310,6 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -360,7 +345,6 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
             group.items.extend(T::extend(cx, args))
         })];
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
-    const TYPE: AttributeType = T::TYPE;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if let Some(first_span) = self.first_span {
diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
index 8f040ffb9d4..980366b5c37 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
@@ -1,6 +1,6 @@
 // data structures
 #[doc(hidden)]
-pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
+pub(super) use rustc_feature::{AttributeTemplate, template};
 #[doc(hidden)]
 pub(super) use rustc_hir::attrs::AttributeKind;
 #[doc(hidden)]
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index fbd9a480fbb..c756bce96e2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -1,7 +1,5 @@
 use std::mem;
 
-use rustc_feature::AttributeType;
-
 use super::prelude::*;
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
@@ -155,8 +153,7 @@ pub(crate) struct CoherenceIsCoreParser;
 impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser {
     const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
-    const TYPE: AttributeType = AttributeType::CrateLevel;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
 }
 
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index b3ab1d3edd6..d7998048be5 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -6,7 +6,7 @@ use std::sync::LazyLock;
 use private::Sealed;
 use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
 use rustc_errors::{Diag, Diagnostic, Level};
-use rustc_feature::{AttributeTemplate, AttributeType};
+use rustc_feature::AttributeTemplate;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::{AttributeLint, AttributeLintKind};
 use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
@@ -83,7 +83,6 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
     pub(super) template: AttributeTemplate,
     pub(super) accept_fn: AcceptFn<S>,
     pub(super) allowed_targets: AllowedTargets,
-    pub(super) attribute_type: AttributeType,
 }
 
 type AcceptFn<S> =
@@ -133,7 +132,6 @@ macro_rules! attribute_parsers {
                                 })
                             }),
                             allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
-                            attribute_type: <$names as crate::attributes::AttributeParser<$stage>>::TYPE,
                         });
                     }
 
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 0fe3c209421..8f2de4af14e 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -272,7 +272,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
 
                             (accept.accept_fn)(&mut cx, args);
                             if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
-                                Self::check_type(accept.attribute_type, target, &mut cx);
                                 Self::check_target(&accept.allowed_targets, target, &mut cx);
                             }
                         }
diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs
index edc496b460c..c52253699b5 100644
--- a/compiler/rustc_attr_parsing/src/target_checking.rs
+++ b/compiler/rustc_attr_parsing/src/target_checking.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 
 use rustc_ast::AttrStyle;
 use rustc_errors::DiagArgValue;
-use rustc_feature::{AttributeType, Features};
+use rustc_feature::Features;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_hir::{MethodKind, Target};
 
@@ -14,6 +14,11 @@ use crate::session_diagnostics::InvalidTarget;
 pub(crate) enum AllowedTargets {
     AllowList(&'static [Policy]),
     AllowListWarnRest(&'static [Policy]),
+    /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
+    /// For crate-level attributes we emit a specific set of lints to warn
+    /// people about accidentally not using them on the crate.
+    /// Only use this for attributes that are *exclusively* valid at the crate level.
+    CrateLevel,
 }
 
 pub(crate) enum AllowedResult {
@@ -43,6 +48,7 @@ impl AllowedTargets {
                     AllowedResult::Warn
                 }
             }
+            AllowedTargets::CrateLevel => AllowedResult::Allowed,
         }
     }
 
@@ -50,6 +56,7 @@ impl AllowedTargets {
         match self {
             AllowedTargets::AllowList(list) => list,
             AllowedTargets::AllowListWarnRest(list) => list,
+            AllowedTargets::CrateLevel => ALL_TARGETS,
         }
         .iter()
         .filter_map(|target| match target {
@@ -74,6 +81,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
         target: Target,
         cx: &mut AcceptContext<'_, 'sess, S>,
     ) {
+        Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
+
         match allowed_targets.is_allowed(target) {
             AllowedResult::Allowed => {}
             AllowedResult::Warn => {
@@ -109,7 +118,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
     }
 
     pub(crate) fn check_type(
-        attribute_type: AttributeType,
+        crate_level: bool,
         target: Target,
         cx: &mut AcceptContext<'_, 'sess, S>,
     ) {
@@ -119,7 +128,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
             return;
         }
 
-        if attribute_type != AttributeType::CrateLevel {
+        if !crate_level {
             return;
         }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index ea264c8064a..6d69040c711 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -716,7 +716,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             return (false, false, None);
         };
 
-        let implemented_trait_item = self.infcx.tcx.associated_item(my_def).trait_item_def_id;
+        let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def);
 
         (
             true,
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 358c0d3db46..7c1a5f44e16 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -64,6 +64,11 @@ builtin_macros_autodiff_ty_activity = {$act} can not be used for this type
 builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}`
 
 builtin_macros_autodiff_width = autodiff width must fit u32, but is {$width}
+
+builtin_macros_avoid_att_syntax = avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
+
+builtin_macros_avoid_intel_syntax = avoid using `.intel_syntax`, Intel syntax is the default
+
 builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
     .label = not applicable here
     .label2 = not a `struct`, `enum` or `union`
@@ -138,6 +143,8 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
 builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
     .suggestion = remove the value
 
+builtin_macros_duplicate_macro_attribute = duplicated attribute
+
 builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
     .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
     .custom = use `std::env::var({$var_expr})` to read the variable at run time
@@ -231,6 +238,8 @@ builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struc
 
 builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field
 
+builtin_macros_incomplete_include = include macro expected single expression in source
+
 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
     .note = only one `#[default]` attribute is needed
     .label = `#[default]` used here
@@ -294,3 +303,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
     .label = not a trait
     .str_lit = try using `#[derive({$sym})]`
     .other = for example, write `#[derive(Debug)]` for `Debug`
+
+builtin_macros_unnameable_test_items = cannot test inner items
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 86b8e1ff8db..ae62b5ea2a0 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,4 +1,3 @@
-use lint::BuiltinLintDiag;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::{AsmMacro, token};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -352,7 +351,7 @@ fn expand_preparsed_asm(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".intel_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    BuiltinLintDiag::AvoidUsingIntelSyntax,
+                    errors::AvoidIntelSyntax,
                 );
             }
             if template_str.contains(".att_syntax") {
@@ -360,7 +359,7 @@ fn expand_preparsed_asm(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".att_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    BuiltinLintDiag::AvoidUsingAttSyntax,
+                    errors::AvoidAttSyntax,
                 );
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 54e8f750337..0993fdc5be4 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -3,9 +3,29 @@ use rustc_errors::{
     Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
     Subdiagnostic,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Ident, Span, Symbol};
 
+#[derive(LintDiagnostic)]
+#[diag(builtin_macros_avoid_intel_syntax)]
+pub(crate) struct AvoidIntelSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(builtin_macros_avoid_att_syntax)]
+pub(crate) struct AvoidAttSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(builtin_macros_incomplete_include)]
+pub(crate) struct IncompleteInclude;
+
+#[derive(LintDiagnostic)]
+#[diag(builtin_macros_unnameable_test_items)]
+pub(crate) struct UnnameableTestItems;
+
+#[derive(LintDiagnostic)]
+#[diag(builtin_macros_duplicate_macro_attribute)]
+pub(crate) struct DuplicateMacroAttribute;
+
 #[derive(Diagnostic)]
 #[diag(builtin_macros_requires_cfg_pattern)]
 pub(crate) struct RequiresCfgPattern {
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 11b868f81a9..16adaab15c5 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -12,7 +12,6 @@ use rustc_expand::base::{
     DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path,
 };
 use rustc_expand::module::DirOwnership;
-use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::lexer::StripTokens;
 use rustc_parse::parser::ForceCollect;
 use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
@@ -159,7 +158,7 @@ pub(crate) fn expand_include<'cx>(
                     INCOMPLETE_INCLUDE,
                     p.token.span,
                     self.node_id,
-                    BuiltinLintDiag::IncompleteInclude,
+                    errors::IncompleteInclude,
                 );
             }
             Some(expr)
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index a9d91f77560..51089e5a1d3 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -11,7 +11,6 @@ use rustc_errors::DiagCtxtHandle;
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
-use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::Session;
 use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
@@ -165,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
                 i.id,
-                BuiltinLintDiag::UnnameableTestItems,
+                errors::UnnameableTestItems,
             );
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 3a4585d5be9..e26f31dce67 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -5,7 +5,6 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
 use rustc_expand::expand::AstFragment;
 use rustc_feature::AttributeTemplate;
-use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
 use rustc_parse::{exp, parser};
 use rustc_session::errors::report_lit_error;
@@ -49,7 +48,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
                 DUPLICATE_MACRO_ATTRIBUTES,
                 attr.span,
                 ecx.current_expansion.lint_node_id,
-                BuiltinLintDiag::DuplicateMacroAttribute,
+                errors::DuplicateMacroAttribute,
             );
         }
     }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index dd688b8b345..1dd65d38a2b 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -31,7 +31,7 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C
 codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
 
 codegen_ssa_dlltool_fail_import_library =
-    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
+    dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
     {$stdout}
     {$stderr}
 
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 008340e614d..dc500c363f4 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -562,15 +562,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     codegen_fn_attrs
 }
 
-/// If the provided DefId is a method in a trait impl, return the DefId of the method prototype.
-fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    let impl_item = tcx.opt_associated_item(def_id)?;
-    match impl_item.container {
-        ty::AssocItemContainer::Impl => impl_item.trait_item_def_id,
-        _ => None,
-    }
-}
-
 fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
     // Backtrack to the crate root.
     let mut disabled = match tcx.opt_local_parent(did) {
@@ -600,14 +591,15 @@ fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
 /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let Some(trait_item) = opt_trait_item(tcx, def_id) else { return false };
-    tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER)
+    tcx.trait_item_of(def_id).is_some_and(|id| {
+        tcx.codegen_fn_attrs(id).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER)
+    })
 }
 
 /// If the provided DefId is a method in a trait impl, return the value of the `#[align]`
 /// attribute on the method prototype (if any).
 fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
-    tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
+    tcx.codegen_fn_attrs(tcx.trait_item_of(def_id)?).alignment
 }
 
 /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 61ba716d082..47c00bff5c9 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -3,6 +3,8 @@ expand_attributes_on_expressions_experimental =
     .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
     .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
 
+expand_cfg_attr_no_attributes = `#[cfg_attr]` does not expand to any attributes
+
 expand_collapse_debuginfo_illegal =
     illegal value for attribute #[collapse_debuginfo(no|external|yes)]
 
@@ -78,6 +80,10 @@ expand_macro_body_stability =
     .label = invalid body stability attribute
     .label2 = body stability attribute affects this macro
 
+expand_macro_call_unused_doc_comment = unused doc comment
+    .label = rustdoc does not generate documentation for macro invocations
+    .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
+
 expand_macro_const_stability =
     macros cannot have const stability attributes
     .label = invalid const stability attribute
@@ -89,6 +95,13 @@ expand_malformed_feature_attribute =
     malformed `feature` attribute input
     .expected = expected just one word
 
+expand_metavar_still_repeating = variable `{$ident}` is still repeating at this depth
+    .label = expected repetition
+
+expand_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
+    .binder_label = expected repetition
+    .occurrence_label = conflicting repetition
+
 expand_meta_var_dif_seq_matchers = {$msg}
 
 expand_missing_fragment_specifier = missing fragment specifier
@@ -147,6 +160,9 @@ expand_mve_unrecognized_var =
 expand_non_inline_modules_in_proc_macro_input_are_unstable =
     non-inline modules in proc macro input are unstable
 
+expand_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+    .suggestion = use pat_param to preserve semantics
+
 expand_proc_macro_back_compat = using an old version of `{$crate_name}`
     .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
 
@@ -176,11 +192,18 @@ expand_resolve_relative_path =
 
 expand_trace_macro = trace_macro
 
+expand_trailing_semi_macro = trailing semicolon in macro used in expression position
+    .note1 = macro invocations at the end of a block are treated as expressions
+    .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
+
+expand_unknown_macro_variable = unknown macro variable `{$name}`
+
+expand_unused_builtin_attribute = unused attribute `{$attr_name}`
+    .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
+    .suggestion = remove the attribute
+
 expand_unsupported_key_value =
     key-value macro attributes are not supported
 
-expand_var_still_repeating =
-    variable `{$ident}` is still repeating at this depth
-
 expand_wrong_fragment_kind =
     non-{$kind} macro in {$kind} position: {$name}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 15419ab7423..2925e337071 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -21,7 +21,6 @@ use rustc_feature::{
     ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
     REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
 };
-use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::Session;
 use rustc_session::parse::feature_err;
 use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
@@ -315,7 +314,7 @@ impl<'a> StripUnconfigured<'a> {
                 rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
                 cfg_attr.span,
                 ast::CRATE_NODE_ID,
-                BuiltinLintDiag::CfgAttrNoAttributes,
+                crate::errors::CfgAttrNoAttributes,
             );
         }
 
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 6eb5cd65846..c37c2d88d9c 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -3,9 +3,13 @@ use std::borrow::Cow;
 use rustc_ast::ast;
 use rustc_errors::codes::*;
 use rustc_hir::limit::Limit;
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
 
+#[derive(LintDiagnostic)]
+#[diag(expand_cfg_attr_no_attributes)]
+pub(crate) struct CfgAttrNoAttributes;
+
 #[derive(Diagnostic)]
 #[diag(expand_expr_repeat_no_syntax_vars)]
 pub(crate) struct NoSyntaxVarsExprRepeat {
@@ -28,13 +32,30 @@ pub(crate) struct CountRepetitionMisplaced {
 }
 
 #[derive(Diagnostic)]
-#[diag(expand_var_still_repeating)]
-pub(crate) struct VarStillRepeating {
+#[diag(expand_metavar_still_repeating)]
+pub(crate) struct MacroVarStillRepeating {
     #[primary_span]
     pub span: Span,
     pub ident: MacroRulesNormalizedIdent,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(expand_metavar_still_repeating)]
+pub(crate) struct MetaVarStillRepeatingLint {
+    #[label]
+    pub label: Span,
+    pub ident: MacroRulesNormalizedIdent,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(expand_metavariable_wrong_operator)]
+pub(crate) struct MetaVariableWrongOperator {
+    #[label(expand_binder_label)]
+    pub binder: Span,
+    #[label(expand_occurrence_label)]
+    pub occurrence: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(expand_meta_var_dif_seq_matchers)]
 pub(crate) struct MetaVarsDifSeqMatchers {
@@ -43,6 +64,12 @@ pub(crate) struct MetaVarsDifSeqMatchers {
     pub msg: String,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(expand_unknown_macro_variable)]
+pub(crate) struct UnknownMacroVariable {
+    pub name: MacroRulesNormalizedIdent,
+}
+
 #[derive(Diagnostic)]
 #[diag(expand_resolve_relative_path)]
 pub(crate) struct ResolveRelativePath {
@@ -345,6 +372,15 @@ pub(crate) struct DuplicateMatcherBinding {
     pub prev: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(expand_duplicate_matcher_binding)]
+pub(crate) struct DuplicateMatcherBindingLint {
+    #[label]
+    pub span: Span,
+    #[label(expand_label2)]
+    pub prev: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(expand_missing_fragment_specifier)]
 #[note]
@@ -501,3 +537,39 @@ pub(crate) struct MacroArgsBadDelimSugg {
     #[suggestion_part(code = ")")]
     pub close: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(expand_macro_call_unused_doc_comment)]
+#[help]
+pub(crate) struct MacroCallUnusedDocComment {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(expand_or_patterns_back_compat)]
+pub(crate) struct OrPatternsBackCompat {
+    #[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
+    pub span: Span,
+    pub suggestion: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(expand_trailing_semi_macro)]
+pub(crate) struct TrailingMacro {
+    #[note(expand_note1)]
+    #[note(expand_note2)]
+    pub is_trailing: bool,
+    pub name: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(expand_unused_builtin_attribute)]
+pub(crate) struct UnusedBuiltinAttribute {
+    #[note]
+    pub invoc_span: Span,
+    pub attr_name: Symbol,
+    pub macro_name: String,
+    #[suggestion(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 38e057d2776..4c0e0bbfe26 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -25,7 +25,6 @@ use rustc_parse::parser::{
     token_descr,
 };
 use rustc_session::Session;
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::SyntaxContext;
@@ -2183,7 +2182,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                     UNUSED_DOC_COMMENTS,
                     current_span,
                     self.cx.current_expansion.lint_node_id,
-                    BuiltinLintDiag::UnusedDocComment(attr.span),
+                    crate::errors::MacroCallUnusedDocComment { span: attr.span },
                 );
             } else if rustc_attr_parsing::is_builtin_attr(attr)
                 && !AttributeParser::<Early>::is_parsed_attribute(&attr.path())
@@ -2196,7 +2195,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         UNUSED_ATTRIBUTES,
                         attr.span,
                         self.cx.current_expansion.lint_node_id,
-                        BuiltinLintDiag::UnusedBuiltinAttribute {
+                        crate::errors::UnusedBuiltinAttribute {
                             attr_name,
                             macro_name: pprust::path_to_string(&call.path),
                             invoc_span: call.path.span,
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index faeae1f494e..ebd6e887f7d 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -108,8 +108,7 @@
 use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{DUMMY_NODE_ID, NodeId};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::MultiSpan;
-use rustc_lint_defs::BuiltinLintDiag;
+use rustc_errors::DecorateDiagCompat;
 use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
 use rustc_session::parse::ParseSess;
 use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
@@ -245,9 +244,12 @@ fn check_binders(
             // There are 3 possibilities:
             if let Some(prev_info) = binders.get(&name) {
                 // 1. The meta-variable is already bound in the current LHS: This is an error.
-                let mut span = MultiSpan::from_span(span);
-                span.push_span_label(prev_info.span, "previous declaration");
-                buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding);
+                buffer_lint(
+                    psess,
+                    span,
+                    node_id,
+                    errors::DuplicateMatcherBindingLint { span, prev: prev_info.span },
+                );
             } else if get_binder_info(macros, binders, name).is_none() {
                 // 2. The meta-variable is free: This is a binder.
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -579,7 +581,7 @@ fn check_ops_is_prefix(
             return;
         }
     }
-    buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name));
+    buffer_lint(psess, span, node_id, errors::UnknownMacroVariable { name });
 }
 
 /// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -604,29 +606,42 @@ fn ops_is_prefix(
     psess: &ParseSess,
     node_id: NodeId,
     span: Span,
-    name: MacroRulesNormalizedIdent,
+    ident: MacroRulesNormalizedIdent,
     binder_ops: &[KleeneToken],
     occurrence_ops: &[KleeneToken],
 ) {
     for (i, binder) in binder_ops.iter().enumerate() {
         if i >= occurrence_ops.len() {
-            let mut span = MultiSpan::from_span(span);
-            span.push_span_label(binder.span, "expected repetition");
-            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name));
+            buffer_lint(
+                psess,
+                span,
+                node_id,
+                errors::MetaVarStillRepeatingLint { label: binder.span, ident },
+            );
             return;
         }
         let occurrence = &occurrence_ops[i];
         if occurrence.op != binder.op {
-            let mut span = MultiSpan::from_span(span);
-            span.push_span_label(binder.span, "expected repetition");
-            span.push_span_label(occurrence.span, "conflicting repetition");
-            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator);
+            buffer_lint(
+                psess,
+                span,
+                node_id,
+                errors::MetaVariableWrongOperator {
+                    binder: binder.span,
+                    occurrence: occurrence.span,
+                },
+            );
             return;
         }
     }
 }
 
-fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) {
+fn buffer_lint(
+    psess: &ParseSess,
+    span: Span,
+    node_id: NodeId,
+    diag: impl Into<DecorateDiagCompat>,
+) {
     // Macros loaded from other crates have dummy node ids.
     if node_id != DUMMY_NODE_ID {
         psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 8b43f852b26..946265eba8b 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -17,7 +17,6 @@ use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::MacroKinds;
 use rustc_hir::find_attr;
-use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
 };
@@ -90,7 +89,7 @@ impl<'a> ParserAnyMacro<'a> {
                     SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
                     parser.token.span,
                     lint_node_id,
-                    BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident),
+                    errors::TrailingMacro { is_trailing: is_trailing_mac, name: macro_ident },
                 );
             }
             parser.bump();
@@ -1425,7 +1424,7 @@ fn check_matcher_core<'tt>(
                             RUST_2021_INCOMPATIBLE_OR_PATTERNS,
                             span,
                             ast::CRATE_NODE_ID,
-                            BuiltinLintDiag::OrPatternsBackCompat(span, suggestion),
+                            errors::OrPatternsBackCompat { span, suggestion },
                         );
                     }
                     match is_in_follow(next_token, kind) {
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index ed8aa71d59d..6a3f1f62c91 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -17,8 +17,8 @@ use rustc_span::{
 use smallvec::{SmallVec, smallvec};
 
 use crate::errors::{
-    CountRepetitionMisplaced, MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar,
-    NoSyntaxVarsExprRepeat, VarStillRepeating,
+    CountRepetitionMisplaced, MacroVarStillRepeating, MetaVarsDifSeqMatchers, MustRepeatOnce,
+    MveUnrecognizedVar, NoSyntaxVarsExprRepeat,
 };
 use crate::mbe::macro_parser::NamedMatch;
 use crate::mbe::macro_parser::NamedMatch::*;
@@ -483,7 +483,7 @@ fn transcribe_metavar<'tx>(
         }
         MatchedSeq(..) => {
             // We were unable to descend far enough. This is an error.
-            return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
+            return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident }));
         }
     };
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 75551fe4c19..493236718a8 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3220,12 +3220,21 @@ pub struct ImplItem<'hir> {
     pub owner_id: OwnerId,
     pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
-    pub defaultness: Defaultness,
+    pub impl_kind: ImplItemImplKind,
     pub span: Span,
-    pub vis_span: Span,
     pub has_delayed_lints: bool,
-    /// When we are in a trait impl, link to the trait-item's id.
-    pub trait_item_def_id: Option<DefId>,
+}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub enum ImplItemImplKind {
+    Inherent {
+        vis_span: Span,
+    },
+    Trait {
+        defaultness: Defaultness,
+        /// Item in the trait that this item implements
+        trait_item_def_id: Result<DefId, ErrorGuaranteed>,
+    },
 }
 
 impl<'hir> ImplItem<'hir> {
@@ -3239,6 +3248,13 @@ impl<'hir> ImplItem<'hir> {
         ImplItemId { owner_id: self.owner_id }
     }
 
+    pub fn vis_span(&self) -> Option<Span> {
+        match self.impl_kind {
+            ImplItemImplKind::Trait { .. } => None,
+            ImplItemImplKind::Inherent { vis_span, .. } => Some(vis_span),
+        }
+    }
+
     expect_methods_self_kind! {
         expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body);
         expect_fn,    (&FnSig<'hir>, BodyId),   ImplItemKind::Fn(ty, body),    (ty, *body);
@@ -4985,7 +5001,7 @@ mod size_asserts {
     static_assert_size!(GenericBound<'_>, 64);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 40);
-    static_assert_size!(ImplItem<'_>, 96);
+    static_assert_size!(ImplItem<'_>, 88);
     static_assert_size!(ImplItemKind<'_>, 40);
     static_assert_size!(Item<'_>, 88);
     static_assert_size!(ItemKind<'_>, 64);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 25a7ae239f3..eb682f32111 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1257,18 +1257,21 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
         owner_id: _,
         ident,
         ref generics,
+        ref impl_kind,
         ref kind,
-        ref defaultness,
         span: _,
-        vis_span: _,
         has_delayed_lints: _,
-        trait_item_def_id: _,
     } = *impl_item;
 
     try_visit!(visitor.visit_ident(ident));
     try_visit!(visitor.visit_generics(generics));
-    try_visit!(visitor.visit_defaultness(defaultness));
     try_visit!(visitor.visit_id(impl_item.hir_id()));
+    match impl_kind {
+        ImplItemImplKind::Inherent { vis_span: _ } => {}
+        ImplItemImplKind::Trait { defaultness, trait_item_def_id: _ } => {
+            try_visit!(visitor.visit_defaultness(defaultness));
+        }
+    }
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
             try_visit!(visitor.visit_ty_unambig(ty));
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 08b344638dd..886ebddc75c 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1009,8 +1009,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
             res = res.and(check_associated_item(tcx, def_id));
             let assoc_item = tcx.associated_item(def_id);
             match assoc_item.container {
-                ty::AssocItemContainer::Impl => {}
-                ty::AssocItemContainer::Trait => {
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}
+                ty::AssocContainer::Trait => {
                     res = res.and(check_trait_item(tcx, def_id));
                 }
             }
@@ -1026,8 +1026,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
             res = res.and(check_associated_item(tcx, def_id));
             let assoc_item = tcx.associated_item(def_id);
             match assoc_item.container {
-                ty::AssocItemContainer::Impl => {}
-                ty::AssocItemContainer::Trait => {
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}
+                ty::AssocContainer::Trait => {
                     res = res.and(check_trait_item(tcx, def_id));
                 }
             }
@@ -1043,8 +1043,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
 
             let assoc_item = tcx.associated_item(def_id);
             let has_type = match assoc_item.container {
-                ty::AssocItemContainer::Impl => true,
-                ty::AssocItemContainer::Trait => {
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
+                ty::AssocContainer::Trait => {
                     tcx.ensure_ok().explicit_item_bounds(def_id);
                     tcx.ensure_ok().explicit_item_self_bounds(def_id);
                     if tcx.is_conditionally_const(def_id) {
@@ -1177,12 +1177,9 @@ fn check_impl_items_against_trait<'tcx>(
 
     for &impl_item in impl_item_refs {
         let ty_impl_item = tcx.associated_item(impl_item);
-        let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
-            tcx.associated_item(trait_item_id)
-        } else {
-            // Checked in `associated_item`.
-            tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
-            continue;
+        let ty_trait_item = match ty_impl_item.expect_trait_impl() {
+            Ok(trait_item_id) => tcx.associated_item(trait_item_id),
+            Err(ErrorGuaranteed { .. }) => continue,
         };
 
         let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index e4827256193..946c4936bb6 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -37,7 +37,7 @@ pub(super) fn compare_impl_item(
     impl_item_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
     let impl_item = tcx.associated_item(impl_item_def_id);
-    let trait_item = tcx.associated_item(impl_item.trait_item_def_id.unwrap());
+    let trait_item = tcx.associated_item(impl_item.expect_trait_impl()?);
     let impl_trait_ref =
         tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap().instantiate_identity();
     debug!(?impl_trait_ref);
@@ -298,14 +298,9 @@ fn compare_method_predicate_entailment<'tcx>(
     // compatible with that of the trait method. We do this by
     // checking that `impl_fty <: trait_fty`.
     //
-    // FIXME. Unfortunately, this doesn't quite work right now because
-    // associated type normalization is not integrated into subtype
-    // checks. For the comparison to be valid, we need to
-    // normalize the associated types in the impl/trait methods
-    // first. However, because function types bind regions, just
-    // calling `FnCtxt::normalize` would have no effect on
-    // any associated types appearing in the fn arguments or return
-    // type.
+    // FIXME: We manually instantiate the trait method here as we need
+    // to manually compute its implied bounds. Otherwise this could just
+    // be `ocx.sub(impl_sig, trait_sig)`.
 
     let mut wf_tys = FxIndexSet::default();
 
@@ -446,7 +441,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     impl_m_def_id: LocalDefId,
 ) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
     let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());
-    let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap());
+    let trait_m = tcx.associated_item(impl_m.expect_trait_impl()?);
     let impl_trait_ref =
         tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity();
     // First, check a few of the same things as `compare_impl_method`,
@@ -1449,8 +1444,10 @@ fn compare_self_type<'tcx>(
 
     let self_string = |method: ty::AssocItem| {
         let untransformed_self_ty = match method.container {
-            ty::AssocItemContainer::Impl => impl_trait_ref.self_ty(),
-            ty::AssocItemContainer::Trait => tcx.types.self_param,
+            ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
+                impl_trait_ref.self_ty()
+            }
+            ty::AssocContainer::Trait => tcx.types.self_param,
         };
         let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0);
         let (infcx, param_env) = tcx
@@ -2458,8 +2455,12 @@ fn param_env_with_gat_bounds<'tcx>(
 
     for impl_ty in impl_tys_to_install {
         let trait_ty = match impl_ty.container {
-            ty::AssocItemContainer::Trait => impl_ty,
-            ty::AssocItemContainer::Impl => tcx.associated_item(impl_ty.trait_item_def_id.unwrap()),
+            ty::AssocContainer::InherentImpl => bug!(),
+            ty::AssocContainer::Trait => impl_ty,
+            ty::AssocContainer::TraitImpl(Err(_)) => continue,
+            ty::AssocContainer::TraitImpl(Ok(trait_item_def_id)) => {
+                tcx.associated_item(trait_item_def_id)
+            }
         };
 
         let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6270fb24ba7..0a555c7f6e9 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -933,12 +933,11 @@ pub(crate) fn check_associated_item(
 
         // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
         // other `Foo` impls are incoherent.
-        tcx.ensure_ok()
-            .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?;
+        tcx.ensure_ok().coherent_trait(tcx.parent(item.trait_item_or_self()?))?;
 
         let self_ty = match item.container {
-            ty::AssocItemContainer::Trait => tcx.types.self_param,
-            ty::AssocItemContainer::Impl => {
+            ty::AssocContainer::Trait => tcx.types.self_param,
+            ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
                 tcx.type_of(item.container_id(tcx)).instantiate_identity()
             }
         };
@@ -967,7 +966,7 @@ pub(crate) fn check_associated_item(
                 check_method_receiver(wfcx, hir_sig, item, self_ty)
             }
             ty::AssocKind::Type { .. } => {
-                if let ty::AssocItemContainer::Trait = item.container {
+                if let ty::AssocContainer::Trait = item.container {
                     check_associated_type_bounds(wfcx, item, span)
                 }
                 if item.defaultness(tcx).has_value() {
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 126ffabd448..dd3590f9ac5 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -111,9 +111,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         }
 
         Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
-            let assoc_item = tcx.associated_item(def_id);
-            let trait_assoc_predicates =
-                tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap());
+            let trait_item_def_id = tcx.trait_item_of(def_id).unwrap();
+            let trait_assoc_predicates = tcx.explicit_predicates_of(trait_item_def_id);
 
             let impl_assoc_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
             let impl_def_id = tcx.parent(fn_def_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 62125c99d80..8cbf17162e3 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -125,8 +125,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
         Some(ty::ImplTraitInTraitData::Impl { fn_def_id }) => {
             match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
                 Ok(map) => {
-                    let assoc_item = tcx.associated_item(def_id);
-                    return map[&assoc_item.trait_item_def_id.unwrap()];
+                    let trait_item_def_id = tcx.trait_item_of(def_id).unwrap();
+                    return map[&trait_item_def_id];
                 }
                 Err(_) => {
                     return ty::EarlyBinder::bind(Ty::new_error_with_message(
@@ -198,7 +198,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                 }
             }
             ImplItemKind::Type(ty) => {
-                if tcx.impl_trait_ref(tcx.hir_get_parent_item(hir_id)).is_none() {
+                if let ImplItemImplKind::Inherent { .. } = item.impl_kind {
                     check_feature_inherent_assoc_ty(tcx, item.span);
                 }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 0b3d50ff219..7370124e800 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1021,7 +1021,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let container_id = assoc_item.container_id(tcx);
                 debug!(?def_id, ?container, ?container_id);
                 match container {
-                    ty::AssocItemContainer::Trait => {
+                    ty::AssocContainer::Trait => {
                         if let Err(e) = callee::check_legal_trait_for_method_call(
                             tcx,
                             path_span,
@@ -1033,7 +1033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.set_tainted_by_errors(e);
                         }
                     }
-                    ty::AssocItemContainer::Impl => {
+                    ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
                         if segments.len() == 1 {
                             // `<T>::assoc` will end up here, and so
                             // can `T::assoc`. If this came from an
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 94b635c41b4..44a6084ebd5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2354,7 +2354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We want it to always point to the trait item.
             // If we're pointing at an inherent function, we don't need to do anything,
             // so we fetch the parent and verify if it's a trait item.
-            && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
+            && let Ok(maybe_trait_item_def_id) = assoc_item.trait_item_or_self()
             && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
             // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
             && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index d7ddbcc8b53..1998a1884b7 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1882,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if segment.ident.name == sym::clone
             && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| {
                     let assoc_item = self.tcx.associated_item(did);
-                    assoc_item.container == ty::AssocItemContainer::Trait
+                    assoc_item.container == ty::AssocContainer::Trait
                         && assoc_item.container_id(self.tcx) == clone_trait_did
                 })
             // If that clone call hasn't already dereferenced the self type (i.e. don't give this
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 129de32fd4a..7f5397a7926 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -278,8 +278,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
     {
         if let Some(item) = tcx.opt_associated_item(def_id.into())
             && let ty::AssocKind::Const { .. } = item.kind
-            && let ty::AssocItemContainer::Impl = item.container
-            && let Some(trait_item_def_id) = item.trait_item_def_id
+            && let ty::AssocContainer::TraitImpl(Ok(trait_item_def_id)) = item.container
         {
             let impl_def_id = item.container_id(tcx);
             let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 52a8eff984b..4185f7f6996 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -18,8 +18,8 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::elaborate::supertrait_def_ids;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
 use rustc_middle::ty::{
-    self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind,
-    ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast,
+    self, AssocContainer, AssocItem, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd,
+    Ty, TyCtxt, TypeVisitableExt, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -528,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ProbeScope::Single(def_id) => {
                     let item = self.tcx.associated_item(def_id);
                     // FIXME(fn_delegation): Delegation to inherent methods is not yet supported.
-                    assert_eq!(item.container, AssocItemContainer::Trait);
+                    assert_eq!(item.container, AssocContainer::Trait);
 
                     let trait_def_id = self.tcx.parent(def_id);
                     let trait_span = self.tcx.def_span(trait_def_id);
@@ -1659,7 +1659,7 @@ impl<'tcx> Pick<'tcx> {
     /// Do not use for type checking.
     pub(crate) fn differs_from(&self, other: &Self) -> bool {
         let Self {
-            item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ },
+            item: AssocItem { def_id, kind: _, container: _ },
             kind: _,
             import_ids: _,
             autoderefs: _,
@@ -1702,7 +1702,7 @@ impl<'tcx> Pick<'tcx> {
                         tcx.def_path_str(self.item.def_id),
                     ));
                 }
-                (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => {
+                (ty::AssocKind::Const { name }, ty::AssocContainer::Trait) => {
                     let def_id = self.item.container_id(tcx);
                     lint.span_suggestion(
                         span,
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index d83b18cbc2d..6f6666f8c76 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -30,6 +30,9 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
 interface_input_file_would_be_overwritten =
     the input file "{$path}" would be overwritten by the generated executable
 
+interface_invalid_crate_type_value = invalid `crate_type` value
+    .suggestion = did you mean
+
 interface_mixed_bin_crate =
     cannot mix `bin` crate type with others
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index d1082eaf617..727e09c7562 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -1,7 +1,7 @@
 use std::io;
 use std::path::Path;
 
-use rustc_macros::Diagnostic;
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
@@ -108,3 +108,18 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
     pub feature: &'a str,
     pub enabled: &'a str,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(interface_invalid_crate_type_value)]
+pub(crate) struct UnknownCrateTypes {
+    #[subdiagnostic]
+    pub sugg: Option<UnknownCrateTypesSub>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(interface_suggestion, code = r#""{snippet}""#, applicability = "maybe-incorrect")]
+pub(crate) struct UnknownCrateTypesSub {
+    #[primary_span]
+    pub span: Span,
+    pub snippet: Symbol,
+}
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 04006f3e446..061c764e619 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -13,9 +13,8 @@ use rustc_errors::LintBuffer;
 use rustc_metadata::{DylibError, load_symbol_from_dylib};
 use rustc_middle::ty::CurrentGcx;
 use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
-use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
-use rustc_session::{EarlyDiagCtxt, Session, filesearch};
+use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMapInputs;
@@ -468,7 +467,10 @@ pub(crate) fn check_attr_crate_type(
                         lint::builtin::UNKNOWN_CRATE_TYPES,
                         ast::CRATE_NODE_ID,
                         span,
-                        BuiltinLintDiag::UnknownCrateTypes { span, candidate },
+                        errors::UnknownCrateTypes {
+                            sugg: candidate
+                                .map(|cand| errors::UnknownCrateTypesSub { span, snippet: cand }),
+                        },
                     );
                 }
             } else {
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 417e5a97069..5b98c9fafaa 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -40,12 +40,6 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order
 lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
     .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
 
-lint_avoid_att_syntax =
-    avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
-
-lint_avoid_intel_syntax =
-    avoid using `.intel_syntax`, Intel syntax is the default
-
 lint_bad_attribute_argument = bad attribute argument
 
 lint_bad_opt_access = {$msg}
@@ -187,12 +181,6 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
-lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait
-    .help = consider implementing the trait by hand, or remove the `packed` attribute
-
-lint_cfg_attr_no_attributes =
-    `#[cfg_attr]` does not expand to any attributes
-
 lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
 
 lint_closure_returning_async_block = closure returning async block can be made into an async closure
@@ -249,11 +237,6 @@ lint_dropping_copy_types = calls to `std::mem::drop` with a value that implement
 lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
     .label = argument has type `{$arg_ty}`
 
-lint_duplicate_macro_attribute =
-    duplicated attribute
-
-lint_duplicate_matcher_binding = duplicate matcher binding
-
 lint_enum_intrinsics_mem_discriminant =
     the return value of `mem::discriminant` is unspecified when called with a non-enum type
     .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum
@@ -409,9 +392,6 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
 lint_improper_ctypes_union_layout_reason = this union has unspecified layout
 lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
 
-lint_incomplete_include =
-    include macro expected single expression in source
-
 lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly
     .label = use a different label that doesn't start with `0` or `1`
     .help = start numbering with `2` instead
@@ -427,9 +407,6 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly
     .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro
 
-lint_invalid_crate_type_value = invalid `crate_type` value
-    .suggestion = did you mean
-
 # FIXME: we should ordinalize $valid_up_to when we add support for doing so
 lint_invalid_from_utf8_checked = calls to `{$method}` with an invalid literal always return an error
     .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
@@ -470,15 +447,9 @@ lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a point
     .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance
     .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut`
 
-lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
-    .label = the attribute is introduced here
-
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
-lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
-    .note = the macro is defined here
-
 lint_macro_expr_fragment_specifier_2024_migration =
     the `expr` fragment specifier will accept more expressions in the 2024 edition
     .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier
@@ -486,10 +457,6 @@ lint_macro_is_private = macro `{$ident}` is private
 
 lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
 
-lint_macro_use_deprecated =
-    applying the `#[macro_use]` attribute to an `extern crate` item is deprecated
-    .help = remove it and import macros at use sites with a `use` item instead
-
 lint_malformed_attribute = malformed lint attribute input
 
 lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
@@ -499,10 +466,6 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
     .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
     .suggestion = you might have meant to use `Iterator::for_each`
 
-lint_metavariable_still_repeating = variable `{$name}` is still repeating at this depth
-
-lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
-
 lint_mismatched_lifetime_syntaxes_eliding_while_named =
     eliding a lifetime that's named elsewhere is confusing
 
@@ -548,9 +511,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_mixed =
 lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths =
     use `'_` for type paths
 
-lint_missing_unsafe_on_extern = extern blocks should be unsafe
-    .suggestion = needs `unsafe` before the extern keyword
-
 lint_mixed_script_confusables =
     the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
     .includes_note = the usage includes {$includes}
@@ -674,9 +634,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
 
-lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
-    .suggestion = use pat_param to preserve semantics
-
 lint_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location}
     .label = not found from {$location}
     .help = import `macro_rules` with `use` to make it callable above its definition
@@ -719,9 +676,6 @@ lint_pattern_in_foreign = patterns aren't allowed in foreign function declaratio
 lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported
     .suggestion = consider making the `extern crate` item publicly accessible
 
-lint_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope
-    .label = names from parent modules are not accessible without an explicit import
-
 lint_query_instability = using `{$query}` can result in unstable query results
     .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
 
@@ -762,9 +716,6 @@ lint_redundant_semicolons_suggestion = remove {$multiple_semicolons ->
         *[false] this semicolon
     }
 
-lint_reexport_private_dependency =
-    {$kind} `{$name}` from private dependency '{$krate}' is re-exported
-
 lint_remove_mut_from_pattern = remove `mut` from the parameter
 
 lint_removed_lint = lint `{$name}` has been removed: {$reason}
@@ -826,10 +777,6 @@ lint_symbol_intern_string_literal = using `Symbol::intern` on a string literal
 lint_too_large_char_cast = value exceeds maximum `char` value
     .note = maximum valid `char` value is `0x10FFFF`
 
-lint_trailing_semi_macro = trailing semicolon in macro used in expression position
-    .note1 = macro invocations at the end of a block are treated as expressions
-    .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
-
 lint_ty_qualified = usage of qualified `ty::{$ty}`
     .suggestion = try importing it and using it unqualified
 
@@ -935,13 +882,9 @@ lint_unknown_lint =
         *[false] did you mean: `{$replace}`
     }
 
-lint_unknown_macro_variable = unknown macro variable `{$name}`
-
 lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
     .help = add `#![register_tool({$tool_name})]` to the crate root
 
-lint_unnameable_test_items = cannot test inner items
-
 lint_unnecessary_qualification = unnecessary qualification
     .suggestion = remove the unnecessary path segments
 
@@ -964,10 +907,6 @@ lint_untranslatable_diag = diagnostics should be created using translatable mess
 lint_unused_allocation = unnecessary allocation, use `&` instead
 lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
 
-lint_unused_builtin_attribute = unused attribute `{$attr_name}`
-    .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
-    .suggestion = remove the attribute
-
 lint_unused_closure =
     unused {$pre}{$count ->
         [one] closure
@@ -993,14 +932,6 @@ lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
 lint_unused_delim = unnecessary {$delim} around {$item}
     .suggestion = remove these {$delim}
 
-lint_unused_doc_comment = unused doc comment
-    .label = rustdoc does not generate documentation for macro invocations
-    .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
-
-lint_unused_extern_crate = unused extern crate
-    .label = unused
-    .suggestion = remove the unused `extern crate`
-
 lint_unused_import_braces = braces around {$node} is unnecessary
 
 lint_unused_imports = {$num_snippets ->
@@ -1014,15 +945,11 @@ lint_unused_imports = {$num_snippets ->
         }
     .help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module
 
-lint_unused_label = unused label
-
 lint_unused_lifetime = lifetime parameter `{$ident}` never used
     .suggestion = elide the unused lifetime
 
 lint_unused_macro_definition = unused macro definition: `{$name}`
 
-lint_unused_macro_use = unused `#[macro_use]` import
-
 lint_unused_op = unused {$op} that must be used
     .label = the {$op} produces a value
     .suggestion = use `let _ = ...` to ignore the resulting value
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c3c0a34df71..75a0f89321b 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -29,12 +29,12 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_hir::intravisit::FnKind as HirFnKind;
-use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin, find_attr};
+use rustc_hir::{Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr};
 use rustc_middle::bug;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
+use rustc_middle::ty::{self, AssocContainer, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
 use rustc_session::lint::FutureIncompatibilityReason;
 // hardwired lints from rustc_lint_defs
 pub use rustc_session::lint::builtin::*;
@@ -61,7 +61,6 @@ use crate::lints::{
     BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
     BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
 };
-use crate::nonstandard_style::{MethodLateContext, method_context};
 use crate::{
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
     fluent_generated as fluent,
@@ -469,14 +468,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
-        let context = method_context(cx, impl_item.owner_id.def_id);
+        let container = cx.tcx.associated_item(impl_item.owner_id.def_id).container;
 
-        match context {
+        match container {
             // If the method is an impl for a trait, don't doc.
-            MethodLateContext::TraitImpl => return,
-            MethodLateContext::TraitAutoImpl => {}
+            AssocContainer::TraitImpl(_) => return,
+            AssocContainer::Trait => {}
             // If the method is an impl for an item with docs_hidden, don't doc.
-            MethodLateContext::PlainImpl => {
+            AssocContainer::InherentImpl => {
                 let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id());
                 let impl_ty = cx.tcx.type_of(parent).instantiate_identity();
                 let outerdef = match impl_ty.kind() {
@@ -1321,9 +1320,8 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
-        // Only lint inherent impl items.
-        if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
-            self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
+        if let ImplItemImplKind::Inherent { vis_span } = impl_item.impl_kind {
+            self.perform_lint(cx, "item", impl_item.owner_id.def_id, vis_span, false);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 7300490b838..9029ee04471 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -64,17 +64,6 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
-            span: macro_span,
-            ns_descr,
-            ident,
-        } => lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns_descr, ident }
-            .decorate_lint(diag),
-        BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
-            lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }
-                .decorate_lint(diag)
-        }
-
         BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
             lints::ElidedLifetimesInPaths {
                 subdiag: elided_lifetime_in_path_suggestion(
@@ -87,10 +76,6 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::UnknownCrateTypes { span, candidate } => {
-            let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate });
-            lints::UnknownCrateTypes { sugg }.decorate_lint(diag);
-        }
         BuiltinLintDiag::UnusedImports {
             remove_whole_use,
             num_to_remove,
@@ -146,9 +131,6 @@ pub fn decorate_builtin_lint(
             stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }
                 .decorate_lint(diag);
         }
-        BuiltinLintDiag::UnusedDocComment(attr_span) => {
-            lints::UnusedDocComment { span: attr_span }.decorate_lint(diag);
-        }
         BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
             let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
             if is_foreign {
@@ -158,12 +140,6 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
-            lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag);
-        }
-        BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
-            lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag);
-        }
         BuiltinLintDiag::ReservedPrefix(label_span, prefix) => {
             lints::ReservedPrefix {
                 label: label_span,
@@ -183,18 +159,6 @@ pub fn decorate_builtin_lint(
                 lints::ReservedMultihash { suggestion }.decorate_lint(diag);
             }
         }
-        BuiltinLintDiag::UnusedBuiltinAttribute {
-            attr_name,
-            macro_name,
-            invoc_span,
-            attr_span,
-        } => {
-            lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name, attr_span }
-                .decorate_lint(diag);
-        }
-        BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
-            lints::TrailingMacro { is_trailing, name }.decorate_lint(diag);
-        }
         BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => {
             lints::BreakWithLabelAndLoop {
                 sub: lints::BreakWithLabelAndLoopSub {
@@ -221,9 +185,6 @@ pub fn decorate_builtin_lint(
             };
             lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag);
         }
-        BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => {
-            lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag);
-        }
         BuiltinLintDiag::SingleUseLifetime {
             param_span,
             use_span: Some((use_span, elide)),
@@ -253,7 +214,6 @@ pub fn decorate_builtin_lint(
                 .decorate_lint(diag);
         }
         BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
-            debug!(?deletion_span);
             lints::UnusedLifetime { deletion_span, ident }.decorate_lint(diag);
         }
         BuiltinLintDiag::NamedArgumentUsedPositionally {
@@ -291,12 +251,6 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
-            lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag);
-        }
-        BuiltinLintDiag::UnusedExternCrate { span, removal_span } => {
-            lints::UnusedExternCrate { span, removal_span }.decorate_lint(diag);
-        }
         BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
             let suggestion_span = vis_span.between(ident_span);
             let code = if vis_span.is_empty() { "use " } else { " use " };
@@ -335,9 +289,6 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => {
-            lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag);
-        }
         BuiltinLintDiag::UnusedQualifications { removal_span } => {
             lints::UnusedQualifications { removal_span }.decorate_lint(diag);
         }
@@ -377,15 +328,10 @@ pub fn decorate_builtin_lint(
             });
             lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag);
         }
-        BuiltinLintDiag::MacroUseDeprecated => {
-            lints::MacroUseDeprecated.decorate_lint(diag);
-        }
-        BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag),
         BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => {
             lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() }
                 .decorate_lint(diag);
         }
-        BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag),
         BuiltinLintDiag::MacroIsPrivate(ident) => {
             lints::MacroIsPrivate { ident }.decorate_lint(diag);
         }
@@ -398,36 +344,6 @@ pub fn decorate_builtin_lint(
         BuiltinLintDiag::UnstableFeature(msg) => {
             lints::UnstableFeature { msg }.decorate_lint(diag);
         }
-        BuiltinLintDiag::AvoidUsingIntelSyntax => {
-            lints::AvoidIntelSyntax.decorate_lint(diag);
-        }
-        BuiltinLintDiag::AvoidUsingAttSyntax => {
-            lints::AvoidAttSyntax.decorate_lint(diag);
-        }
-        BuiltinLintDiag::IncompleteInclude => {
-            lints::IncompleteInclude.decorate_lint(diag);
-        }
-        BuiltinLintDiag::UnnameableTestItems => {
-            lints::UnnameableTestItems.decorate_lint(diag);
-        }
-        BuiltinLintDiag::DuplicateMacroAttribute => {
-            lints::DuplicateMacroAttribute.decorate_lint(diag);
-        }
-        BuiltinLintDiag::CfgAttrNoAttributes => {
-            lints::CfgAttrNoAttributes.decorate_lint(diag);
-        }
-        BuiltinLintDiag::MetaVariableStillRepeating(name) => {
-            lints::MetaVariableStillRepeating { name }.decorate_lint(diag);
-        }
-        BuiltinLintDiag::MetaVariableWrongOperator => {
-            lints::MetaVariableWrongOperator.decorate_lint(diag);
-        }
-        BuiltinLintDiag::DuplicateMatcherBinding => {
-            lints::DuplicateMatcherBinding.decorate_lint(diag);
-        }
-        BuiltinLintDiag::UnknownMacroVariable(name) => {
-            lints::UnknownMacroVariable { name }.decorate_lint(diag);
-        }
         BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
             lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
         }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 56d65ed08f9..b7312484de5 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::lint::AmbiguityErrorDiag;
 use rustc_span::edition::Edition;
-use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
+use rustc_span::{Ident, Span, Symbol, sym};
 
 use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
 use crate::errors::{OverruledAttributeSub, RequestedLevel};
@@ -2536,15 +2536,6 @@ pub(crate) mod unexpected_cfg_value {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_macro_use_deprecated)]
-#[help]
-pub(crate) struct MacroUseDeprecated;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_unused_macro_use)]
-pub(crate) struct UnusedMacroUse;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_private_extern_crate_reexport, code = E0365)]
 pub(crate) struct PrivateExternCrateReexport {
     pub ident: Ident,
@@ -2553,10 +2544,6 @@ pub(crate) struct PrivateExternCrateReexport {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_unused_label)]
-pub(crate) struct UnusedLabel;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_macro_is_private)]
 pub(crate) struct MacroIsPrivate {
     pub ident: Ident,
@@ -2586,50 +2573,6 @@ impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_avoid_intel_syntax)]
-pub(crate) struct AvoidIntelSyntax;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_avoid_att_syntax)]
-pub(crate) struct AvoidAttSyntax;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_incomplete_include)]
-pub(crate) struct IncompleteInclude;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_unnameable_test_items)]
-pub(crate) struct UnnameableTestItems;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_duplicate_macro_attribute)]
-pub(crate) struct DuplicateMacroAttribute;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_cfg_attr_no_attributes)]
-pub(crate) struct CfgAttrNoAttributes;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_metavariable_still_repeating)]
-pub(crate) struct MetaVariableStillRepeating {
-    pub name: MacroRulesNormalizedIdent,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_metavariable_wrong_operator)]
-pub(crate) struct MetaVariableWrongOperator;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_duplicate_matcher_binding)]
-pub(crate) struct DuplicateMatcherBinding;
-
-#[derive(LintDiagnostic)]
-#[diag(lint_unknown_macro_variable)]
-pub(crate) struct UnknownMacroVariable {
-    pub name: MacroRulesNormalizedIdent,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_unused_crate_dependency)]
 #[help]
 pub(crate) struct UnusedCrateDependency {
@@ -2715,22 +2658,6 @@ pub(crate) struct AbsPathWithModuleSugg {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_proc_macro_derive_resolution_fallback)]
-pub(crate) struct ProcMacroDeriveResolutionFallback {
-    #[label]
-    pub span: Span,
-    pub ns_descr: &'static str,
-    pub ident: Ident,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)]
-pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
-    #[note]
-    pub definition: Span,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_hidden_lifetime_parameters)]
 pub(crate) struct ElidedLifetimesInPaths {
     #[subdiagnostic]
@@ -2738,21 +2665,6 @@ pub(crate) struct ElidedLifetimesInPaths {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_invalid_crate_type_value)]
-pub(crate) struct UnknownCrateTypes {
-    #[subdiagnostic]
-    pub sugg: Option<UnknownCrateTypesSub>,
-}
-
-#[derive(Subdiagnostic)]
-#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")]
-pub(crate) struct UnknownCrateTypesSub {
-    #[primary_span]
-    pub span: Span,
-    pub candidate: Symbol,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_unused_imports)]
 pub(crate) struct UnusedImports {
     #[subdiagnostic]
@@ -2810,14 +2722,6 @@ pub(crate) enum RedundantImportSub {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_unused_doc_comment)]
-#[help]
-pub(crate) struct UnusedDocComment {
-    #[label]
-    pub span: Span,
-}
-
-#[derive(LintDiagnostic)]
 pub(crate) enum PatternsInFnsWithoutBody {
     #[diag(lint_pattern_in_foreign)]
     Foreign {
@@ -2841,21 +2745,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_legacy_derive_helpers)]
-pub(crate) struct LegacyDeriveHelpers {
-    #[label]
-    pub span: Span,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_or_patterns_back_compat)]
-pub(crate) struct OrPatternsBackCompat {
-    #[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
-    pub span: Span,
-    pub suggestion: String,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_reserved_prefix)]
 pub(crate) struct ReservedPrefix {
     #[label]
@@ -2876,27 +2765,6 @@ pub(crate) struct RawPrefix {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_unused_builtin_attribute)]
-pub(crate) struct UnusedBuiltinAttribute {
-    #[note]
-    pub invoc_span: Span,
-    pub attr_name: Symbol,
-    pub macro_name: String,
-    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
-    pub attr_span: Span,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_trailing_semi_macro)]
-pub(crate) struct TrailingMacro {
-    #[note(lint_note1)]
-    #[note(lint_note2)]
-    pub is_trailing: bool,
-
-    pub name: Ident,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_break_with_label_and_loop)]
 pub(crate) struct BreakWithLabelAndLoop {
     #[subdiagnostic]
@@ -2939,13 +2807,6 @@ pub(crate) enum DeprecatedWhereClauseLocationSugg {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_missing_unsafe_on_extern)]
-pub(crate) struct MissingUnsafeOnExtern {
-    #[suggestion(code = "unsafe ", applicability = "machine-applicable")]
-    pub suggestion: Span,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_single_use_lifetime)]
 pub(crate) struct SingleUseLifetime {
     #[label(lint_label_param)]
@@ -2993,23 +2854,6 @@ pub(crate) struct NamedArgumentUsedPositionally {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_byte_slice_in_packed_struct_with_derive)]
-#[help]
-pub(crate) struct ByteSliceInPackedStructWithDerive {
-    // FIXME: make this translatable
-    pub ty: String,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_unused_extern_crate)]
-pub(crate) struct UnusedExternCrate {
-    #[label]
-    pub span: Span,
-    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
-    pub removal_span: Span,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_extern_crate_not_idiomatic)]
 pub(crate) struct ExternCrateNotIdiomatic {
     #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
@@ -3057,14 +2901,6 @@ pub(crate) struct HiddenGlobReexports {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(lint_reexport_private_dependency)]
-pub(crate) struct ReexportPrivateDependency {
-    pub name: String,
-    pub kind: String,
-    pub krate: Symbol,
-}
-
-#[derive(LintDiagnostic)]
 #[diag(lint_unnecessary_qualification)]
 pub(crate) struct UnusedQualifications {
     #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 65075cfecfa..7f643a551bb 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr};
 use rustc_middle::hir::nested_filter::All;
-use rustc_middle::ty;
+use rustc_middle::ty::AssocContainer;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::def_id::LocalDefId;
@@ -20,29 +20,6 @@ use crate::lints::{
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 
-#[derive(PartialEq)]
-pub(crate) enum MethodLateContext {
-    TraitAutoImpl,
-    TraitImpl,
-    PlainImpl,
-}
-
-pub(crate) fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext {
-    let item = cx.tcx.associated_item(id);
-    match item.container {
-        ty::AssocItemContainer::Trait => MethodLateContext::TraitAutoImpl,
-        ty::AssocItemContainer::Impl => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) {
-            Some(_) => MethodLateContext::TraitImpl,
-            None => MethodLateContext::PlainImpl,
-        },
-    }
-}
-
-fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool {
-    let item = cx.tcx.associated_item(ii.owner_id);
-    item.trait_item_def_id.is_some()
-}
-
 declare_lint! {
     /// The `non_camel_case_types` lint detects types, variants, traits and
     /// type parameters that don't have camel case names.
@@ -389,8 +366,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
         id: LocalDefId,
     ) {
         match &fk {
-            FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
-                MethodLateContext::PlainImpl => {
+            FnKind::Method(ident, sig, ..) => match cx.tcx.associated_item(id).container {
+                AssocContainer::InherentImpl => {
                     if sig.header.abi != ExternAbi::Rust
                         && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..))
                     {
@@ -398,10 +375,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
                     }
                     self.check_snake_case(cx, "method", ident);
                 }
-                MethodLateContext::TraitAutoImpl => {
+                AssocContainer::Trait => {
                     self.check_snake_case(cx, "trait method", ident);
                 }
-                _ => (),
+                AssocContainer::TraitImpl(_) => {}
             },
             FnKind::ItemFn(ident, _, header) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
@@ -602,7 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) {
         if let hir::ImplItemKind::Const(..) = ii.kind
-            && !assoc_item_in_trait_impl(cx, ii)
+            && let hir::ImplItemImplKind::Inherent { .. } = ii.impl_kind
         {
             NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident);
         }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 2e84233e5a5..40a818a3c9d 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -11,7 +11,7 @@ use rustc_hir_id::{HashStableContext, HirId, ItemLocalId};
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::DefPathHash;
 pub use rustc_span::edition::Edition;
-use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
+use rustc_span::{Ident, Span, Symbol, sym};
 use serde::{Deserialize, Serialize};
 
 pub use self::Level::*;
@@ -620,17 +620,7 @@ pub enum DeprecatedSinceKind {
 #[derive(Debug)]
 pub enum BuiltinLintDiag {
     AbsPathWithModule(Span),
-    ProcMacroDeriveResolutionFallback {
-        span: Span,
-        ns_descr: &'static str,
-        ident: Ident,
-    },
-    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
     ElidedLifetimesInPaths(usize, Span, bool, Span),
-    UnknownCrateTypes {
-        span: Span,
-        candidate: Option<Symbol>,
-    },
     UnusedImports {
         remove_whole_use: bool,
         num_to_remove: usize,
@@ -646,20 +636,11 @@ pub enum BuiltinLintDiag {
         path: String,
         since_kind: DeprecatedSinceKind,
     },
-    UnusedDocComment(Span),
-    UnusedBuiltinAttribute {
-        attr_name: Symbol,
-        macro_name: String,
-        invoc_span: Span,
-        attr_span: Span,
-    },
     PatternsInFnsWithoutBody {
         span: Span,
         ident: Ident,
         is_foreign: bool,
     },
-    LegacyDeriveHelpers(Span),
-    OrPatternsBackCompat(Span, String),
     ReservedPrefix(Span, String),
     /// `'r#` in edition < 2021.
     RawPrefix(Span),
@@ -668,15 +649,11 @@ pub enum BuiltinLintDiag {
         is_string: bool,
         suggestion: Span,
     },
-    TrailingMacro(bool, Ident),
     BreakWithLabelAndLoop(Span),
     UnicodeTextFlow(Span, String),
     UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
     UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
     DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
-    MissingUnsafeOnExtern {
-        suggestion: Span,
-    },
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
         param_span: Span,
@@ -701,14 +678,6 @@ pub enum BuiltinLintDiag {
         /// Indicates if the named argument is used as a width/precision for formatting
         is_formatting_arg: bool,
     },
-    ByteSliceInPackedStructWithDerive {
-        // FIXME: enum of byte/string
-        ty: String,
-    },
-    UnusedExternCrate {
-        span: Span,
-        removal_span: Span,
-    },
     ExternCrateNotIdiomatic {
         vis_span: Span,
         ident_span: Span,
@@ -736,11 +705,6 @@ pub enum BuiltinLintDiag {
         /// The local binding that shadows the glob reexport.
         private_item_span: Span,
     },
-    ReexportPrivateDependency {
-        name: String,
-        kind: String,
-        krate: Symbol,
-    },
     UnusedQualifications {
         /// The span of the unnecessarily-qualified path to remove.
         removal_span: Span,
@@ -763,27 +727,14 @@ pub enum BuiltinLintDiag {
         span: Span,
         typo_name: Option<Symbol>,
     },
-    MacroUseDeprecated,
-    UnusedMacroUse,
     PrivateExternCrateReexport {
         source: Ident,
         extern_crate_span: Span,
     },
-    UnusedLabel,
     MacroIsPrivate(Ident),
     UnusedMacroDefinition(Symbol),
     MacroRuleNeverUsed(usize, Symbol),
     UnstableFeature(DiagMessage),
-    AvoidUsingIntelSyntax,
-    AvoidUsingAttSyntax,
-    IncompleteInclude,
-    UnnameableTestItems,
-    DuplicateMacroAttribute,
-    CfgAttrNoAttributes,
-    MetaVariableStillRepeating(MacroRulesNormalizedIdent),
-    MetaVariableWrongOperator,
-    DuplicateMatcherBinding,
-    UnknownMacroVariable(MacroRulesNormalizedIdent),
     UnusedCrateDependency {
         extern_crate: Symbol,
         local_crate: Symbol,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 110b26c62ef..0c8d1f32e99 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1194,10 +1194,6 @@ impl<'a> CrateMetadataRef<'a> {
         self.root.tables.default_fields.get(self, id).map(|d| d.decode(self))
     }
 
-    fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
-        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
-    }
-
     fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
         self.root
             .tables
@@ -1359,14 +1355,9 @@ impl<'a> CrateMetadataRef<'a> {
             }
             _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
-        let container = self.root.tables.assoc_container.get(self, id).unwrap();
+        let container = self.root.tables.assoc_container.get(self, id).unwrap().decode(self);
 
-        ty::AssocItem {
-            kind,
-            def_id: self.local_def_id(id),
-            trait_item_def_id: self.get_trait_item_def_id(id),
-            container,
-        }
+        ty::AssocItem { kind, def_id: self.local_def_id(id), container }
     }
 
     fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index a7e7e9985f4..db66938457f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -22,7 +22,7 @@ use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::mir::interpret;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
-use rustc_middle::ty::AssocItemContainer;
+use rustc_middle::ty::AssocContainer;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
 use rustc_middle::{bug, span_bug};
@@ -1254,8 +1254,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         DefKind::AssocTy => {
             let assoc_item = tcx.associated_item(def_id);
             match assoc_item.container {
-                ty::AssocItemContainer::Impl => true,
-                ty::AssocItemContainer::Trait => assoc_item.defaultness(tcx).has_value(),
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
+                ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
             }
         }
         DefKind::TyParam => {
@@ -1725,24 +1725,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
         let item = tcx.associated_item(def_id);
 
-        self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx));
-        self.tables.assoc_container.set_some(def_id.index, item.container);
-
-        match item.container {
-            AssocItemContainer::Trait => {
-                if item.is_type() {
-                    self.encode_explicit_item_bounds(def_id);
-                    self.encode_explicit_item_self_bounds(def_id);
-                    if tcx.is_conditionally_const(def_id) {
-                        record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
-                            <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
-                    }
-                }
-            }
-            AssocItemContainer::Impl => {
-                if let Some(trait_item_def_id) = item.trait_item_def_id {
-                    self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
-                }
+        if matches!(item.container, AssocContainer::Trait | AssocContainer::TraitImpl(_)) {
+            self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx));
+        }
+
+        record!(self.tables.assoc_container[def_id] <- item.container);
+
+        if let AssocContainer::Trait = item.container
+            && item.is_type()
+        {
+            self.encode_explicit_item_bounds(def_id);
+            self.encode_explicit_item_self_bounds(def_id);
+            if tcx.is_conditionally_const(def_id) {
+                record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                    <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
             }
         }
         if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1f7d142d330..720970bbaf9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -447,7 +447,6 @@ define_tables! {
     coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>,
     eval_static_initializer: Table<DefIndex, LazyValue<mir::interpret::ConstAllocation<'static>>>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
-    trait_item_def_id: Table<DefIndex, RawDefId>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
     default_fields: Table<DefIndex, LazyValue<DefId>>,
     params_in_repr: Table<DefIndex, LazyValue<DenseBitSet<u32>>>,
@@ -459,7 +458,7 @@ define_tables! {
     def_keys: Table<DefIndex, LazyValue<DefKey>>,
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     variant_data: Table<DefIndex, LazyValue<VariantData>>,
-    assoc_container: Table<DefIndex, ty::AssocItemContainer>,
+    assoc_container: Table<DefIndex, LazyValue<ty::AssocContainer>>,
     macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs
index 34180001f80..4b2dc2c814e 100644
--- a/compiler/rustc_metadata/src/rmeta/parameterized.rs
+++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs
@@ -102,7 +102,7 @@ trivially_parameterized_over_tcx! {
     rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
     rustc_middle::mir::ConstQualifs,
     rustc_middle::ty::AnonConstKind,
-    rustc_middle::ty::AssocItemContainer,
+    rustc_middle::ty::AssocContainer,
     rustc_middle::ty::AsyncDestructor,
     rustc_middle::ty::Asyncness,
     rustc_middle::ty::DeducedParamAttrs,
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 2cb07a28a8a..a882ee4f2b9 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -222,13 +222,6 @@ fixed_size_enum! {
 }
 
 fixed_size_enum! {
-    ty::AssocItemContainer {
-        ( Trait )
-        ( Impl  )
-    }
-}
-
-fixed_size_enum! {
     MacroKind {
         ( Attr   )
         ( Bang   )
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index bea2191c560..4c00b769237 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -318,7 +318,7 @@ trivial! {
     rustc_middle::traits::WellFormedLoc,
     rustc_middle::ty::adjustment::CoerceUnsizedInfo,
     rustc_middle::ty::AssocItem,
-    rustc_middle::ty::AssocItemContainer,
+    rustc_middle::ty::AssocContainer,
     rustc_middle::ty::Asyncness,
     rustc_middle::ty::AsyncDestructor,
     rustc_middle::ty::BoundVariableKind,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 2aa32dfa0d8..0e645a3aae4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1881,6 +1881,7 @@ rustc_queries! {
     }
 
     /// Returns whether the impl or associated function has the `default` keyword.
+    /// Note: This will ICE on inherent impl items. Consider using `AssocItem::defaultness`.
     query defaultness(def_id: DefId) -> hir::Defaultness {
         desc { |tcx| "looking up whether `{}` has `default`", tcx.def_path_str(def_id) }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index a902a8a61e5..768646c7630 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -5,15 +5,17 @@ use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::find_attr;
 use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{Ident, Symbol};
+use rustc_span::{ErrorGuaranteed, Ident, Symbol};
 
 use super::{TyCtxt, Visibility};
 use crate::ty;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
-pub enum AssocItemContainer {
+pub enum AssocContainer {
     Trait,
-    Impl,
+    InherentImpl,
+    /// The `DefId` points to the trait item being implemented.
+    TraitImpl(Result<DefId, ErrorGuaranteed>),
 }
 
 /// Information about an associated item
@@ -21,11 +23,7 @@ pub enum AssocItemContainer {
 pub struct AssocItem {
     pub def_id: DefId,
     pub kind: AssocKind,
-    pub container: AssocItemContainer,
-
-    /// If this is an item in an impl of a trait then this is the `DefId` of
-    /// the associated item on the trait that this implements.
-    pub trait_item_def_id: Option<DefId>,
+    pub container: AssocContainer,
 }
 
 impl AssocItem {
@@ -55,7 +53,34 @@ impl AssocItem {
     ///
     /// [`type_of`]: crate::ty::TyCtxt::type_of
     pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
-        tcx.defaultness(self.def_id)
+        match self.container {
+            AssocContainer::InherentImpl => hir::Defaultness::Final,
+            AssocContainer::Trait | AssocContainer::TraitImpl(_) => tcx.defaultness(self.def_id),
+        }
+    }
+
+    pub fn expect_trait_impl(&self) -> Result<DefId, ErrorGuaranteed> {
+        let AssocContainer::TraitImpl(trait_item_id) = self.container else {
+            bug!("expected item to be in a trait impl: {:?}", self.def_id);
+        };
+        trait_item_id
+    }
+
+    /// If this is a trait impl item, returns the `DefId` of the trait item this implements.
+    /// Otherwise, returns `DefId` for self. Returns an Err in case the trait item was not
+    /// resolved successfully.
+    pub fn trait_item_or_self(&self) -> Result<DefId, ErrorGuaranteed> {
+        match self.container {
+            AssocContainer::TraitImpl(id) => id,
+            AssocContainer::Trait | AssocContainer::InherentImpl => Ok(self.def_id),
+        }
+    }
+
+    pub fn trait_item_def_id(&self) -> Option<DefId> {
+        match self.container {
+            AssocContainer::TraitImpl(Ok(id)) => Some(id),
+            _ => None,
+        }
     }
 
     #[inline]
@@ -71,16 +96,18 @@ impl AssocItem {
     #[inline]
     pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
         match self.container {
-            AssocItemContainer::Impl => None,
-            AssocItemContainer::Trait => Some(tcx.parent(self.def_id)),
+            AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => None,
+            AssocContainer::Trait => Some(tcx.parent(self.def_id)),
         }
     }
 
     #[inline]
     pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
         match self.container {
-            AssocItemContainer::Impl => Some(tcx.parent(self.def_id)),
-            AssocItemContainer::Trait => None,
+            AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => {
+                Some(tcx.parent(self.def_id))
+            }
+            AssocContainer::Trait => None,
         }
     }
 
@@ -156,11 +183,11 @@ impl AssocItem {
             return false;
         }
 
-        let def_id = match (self.container, self.trait_item_def_id) {
-            (AssocItemContainer::Trait, _) => self.def_id,
-            (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
-            // Inherent impl but this attr is only applied to trait assoc items.
-            (AssocItemContainer::Impl, None) => return true,
+        let def_id = match self.container {
+            AssocContainer::Trait => self.def_id,
+            AssocContainer::TraitImpl(Ok(trait_item_did)) => trait_item_did,
+            AssocContainer::TraitImpl(Err(_)) => return false,
+            AssocContainer::InherentImpl => return true,
         };
         find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8ea767dccd3..79700d485c4 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2276,7 +2276,16 @@ impl<'tcx> TyCtxt<'tcx> {
 
         let is_impl_item = match self.hir_node_by_def_id(suitable_region_binding_scope) {
             Node::Item(..) | Node::TraitItem(..) => false,
-            Node::ImplItem(..) => self.is_bound_region_in_impl_item(suitable_region_binding_scope),
+            Node::ImplItem(impl_item) => match impl_item.impl_kind {
+                // For now, we do not try to target impls of traits. This is
+                // because this message is going to suggest that the user
+                // change the fn signature, but they may not be free to do so,
+                // since the signature must match the trait.
+                //
+                // FIXME(#42706) -- in some cases, we could do better here.
+                hir::ImplItemImplKind::Trait { .. } => true,
+                _ => false,
+            },
             _ => false,
         };
 
@@ -2330,21 +2339,6 @@ impl<'tcx> TyCtxt<'tcx> {
         None
     }
 
-    /// Checks if the bound region is in Impl Item.
-    pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool {
-        let container_id = self.parent(suitable_region_binding_scope.to_def_id());
-        if self.impl_trait_ref(container_id).is_some() {
-            // For now, we do not try to target impls of traits. This is
-            // because this message is going to suggest that the user
-            // change the fn signature, but they may not be free to do so,
-            // since the signature must match the trait.
-            //
-            // FIXME(#42706) -- in some cases, we could do better here.
-            return true;
-        }
-        false
-    }
-
     /// Determines whether identifiers in the assembly have strict naming rules.
     /// Currently, only NVPTX* targets need it.
     pub fn has_strict_asm_symbol_naming(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e76993e0542..34ead91b4f6 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -18,8 +18,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::print::{FmtPrinter, Print};
 use crate::ty::{
-    self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 
 /// An `InstanceKind` along with the args that are needed to substitute the instance.
@@ -611,26 +611,23 @@ impl<'tcx> Instance<'tcx> {
                     debug!(" => fn pointer created for virtual call");
                     resolved.def = InstanceKind::ReifyShim(def_id, reason);
                 }
-                // Reify `Trait::method` implementations if KCFI is enabled
-                // FIXME(maurer) only reify it if it is a vtable-safe function
-                _ if tcx.sess.is_sanitizer_kcfi_enabled()
-                    && tcx
-                        .opt_associated_item(def_id)
-                        .and_then(|assoc| assoc.trait_item_def_id)
-                        .is_some() =>
-                {
-                    // If this function could also go in a vtable, we need to `ReifyShim` it with
-                    // KCFI because it can only attach one type per function.
-                    resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason)
-                }
-                // Reify `::call`-like method implementations if KCFI is enabled
-                _ if tcx.sess.is_sanitizer_kcfi_enabled()
-                    && tcx.is_closure_like(resolved.def_id()) =>
-                {
-                    // Reroute through a reify via the *unresolved* instance. The resolved one can't
-                    // be directly reified because it's closure-like. The reify can handle the
-                    // unresolved instance.
-                    resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }
+                _ if tcx.sess.is_sanitizer_kcfi_enabled() => {
+                    // Reify `::call`-like method implementations
+                    if tcx.is_closure_like(resolved.def_id()) {
+                        // Reroute through a reify via the *unresolved* instance. The resolved one can't
+                        // be directly reified because it's closure-like. The reify can handle the
+                        // unresolved instance.
+                        resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }
+                    // Reify `Trait::method` implementations
+                    // FIXME(maurer) only reify it if it is a vtable-safe function
+                    } else if let Some(assoc) = tcx.opt_associated_item(def_id)
+                        && let AssocContainer::Trait | AssocContainer::TraitImpl(Ok(_)) =
+                            assoc.container
+                    {
+                        // If this function could also go in a vtable, we need to `ReifyShim` it with
+                        // KCFI because it can only attach one type per function.
+                        resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason)
+                    }
                 }
                 _ => {}
             }
@@ -683,7 +680,7 @@ impl<'tcx> Instance<'tcx> {
                     && !matches!(
                         tcx.opt_associated_item(def),
                         Some(ty::AssocItem {
-                            container: ty::AssocItemContainer::Trait,
+                            container: ty::AssocContainer::Trait,
                             ..
                         })
                     );
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index da17ec1f9f3..d4c001f625e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1934,6 +1934,11 @@ impl<'tcx> TyCtxt<'tcx> {
         Some((parent, def_kind))
     }
 
+    /// Returns the trait item that is implemented by the given item `DefId`.
+    pub fn trait_item_of(self, def_id: impl IntoQueryParam<DefId>) -> Option<DefId> {
+        self.opt_associated_item(def_id.into_query_param())?.trait_item_def_id()
+    }
+
     /// If the given `DefId` is an associated item of a trait,
     /// returns the `DefId` of the trait; otherwise, returns `None`.
     pub fn trait_of_assoc(self, def_id: DefId) -> Option<DefId> {
@@ -2149,17 +2154,12 @@ impl<'tcx> TyCtxt<'tcx> {
         let Some(item) = self.opt_associated_item(def_id) else {
             return false;
         };
-        if item.container != ty::AssocItemContainer::Impl {
-            return false;
-        }
 
-        let Some(trait_item_def_id) = item.trait_item_def_id else {
+        let AssocContainer::TraitImpl(Ok(trait_item_def_id)) = item.container else {
             return false;
         };
 
-        return !self
-            .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
-            .is_empty();
+        !self.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id).is_empty()
     }
 }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index ab7885905a6..75537caa894 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -75,7 +75,7 @@ passes_const_stable_not_stable =
     .label = attribute specified here
 
 passes_custom_mir_incompatible_dialect_and_phase =
-    The {$dialect} dialect is not compatible with the {$phase} phase
+    the {$dialect} dialect is not compatible with the {$phase} phase
     .dialect_span = this dialect...
     .phase_span = ... is not compatible with this phase
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index fc33405d455..3c2c9683a4d 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -373,31 +373,27 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     /// Automatically generated items marked with `rustc_trivial_field_reads`
     /// will be ignored for the purposes of dead code analysis (see PR #85200
     /// for discussion).
-    fn should_ignore_item(&mut self, def_id: DefId) -> bool {
-        if let Some(impl_of) = self.tcx.trait_impl_of_assoc(def_id) {
-            if !self.tcx.is_automatically_derived(impl_of) {
-                return false;
-            }
-
-            if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
-                && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
+    fn should_ignore_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) -> bool {
+        if let hir::ImplItemImplKind::Trait { .. } = impl_item.impl_kind
+            && let impl_of = self.tcx.parent(impl_item.owner_id.to_def_id())
+            && self.tcx.is_automatically_derived(impl_of)
+            && let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity()
+            && self.tcx.has_attr(trait_ref.def_id, sym::rustc_trivial_field_reads)
+        {
+            if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
+                && let Some(adt_def_id) = adt_def.did().as_local()
             {
-                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity();
-                if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
-                    && let Some(adt_def_id) = adt_def.did().as_local()
-                {
-                    self.ignored_derived_traits.entry(adt_def_id).or_default().insert(trait_of);
-                }
-                return true;
+                self.ignored_derived_traits.entry(adt_def_id).or_default().insert(trait_ref.def_id);
             }
+            return true;
         }
 
         false
     }
 
     fn visit_node(&mut self, node: Node<'tcx>) {
-        if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node
-            && self.should_ignore_item(owner_id.to_def_id())
+        if let Node::ImplItem(impl_item) = node
+            && self.should_ignore_impl_item(impl_item)
         {
             return;
         }
@@ -439,7 +435,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             }
             Node::ImplItem(impl_item) => {
                 let item = self.tcx.local_parent(impl_item.owner_id.def_id);
-                if self.tcx.impl_trait_ref(item).is_none() {
+                if let hir::ImplItemImplKind::Inherent { .. } = impl_item.impl_kind {
                     //// If it's a type whose items are live, then it's live, too.
                     //// This is done to handle the case where, for example, the static
                     //// method of a private type is used, but the type itself is never
@@ -484,13 +480,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     fn check_impl_or_impl_item_live(&mut self, local_def_id: LocalDefId) -> bool {
         let (impl_block_id, trait_def_id) = match self.tcx.def_kind(local_def_id) {
             // assoc impl items of traits are live if the corresponding trait items are live
-            DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => (
-                self.tcx.local_parent(local_def_id),
-                self.tcx
-                    .associated_item(local_def_id)
-                    .trait_item_def_id
-                    .and_then(|def_id| def_id.as_local()),
-            ),
+            DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => {
+                let trait_item_id =
+                    self.tcx.trait_item_of(local_def_id).and_then(|def_id| def_id.as_local());
+                (self.tcx.local_parent(local_def_id), trait_item_id)
+            }
             // impl items are live if the corresponding traits are live
             DefKind::Impl { of_trait: true } => (
                 local_def_id,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 71650c6b9b9..2ee1bd0dfd1 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -21,8 +21,8 @@ use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult};
 use rustc_middle::query::{LocalCrate, Providers};
-use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{AssocContainer, TyCtxt};
 use rustc_session::lint;
 use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL};
 use rustc_span::{Span, Symbol, sym};
@@ -486,8 +486,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         self.check_compatible_stability(ii.owner_id.def_id);
-        let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id());
-        if self.tcx.impl_trait_ref(impl_def_id).is_none() {
+        if let hir::ImplItemImplKind::Inherent { .. } = ii.impl_kind {
             self.check_missing_stability(ii.owner_id.def_id);
             self.check_missing_const_stability(ii.owner_id.def_id);
         }
@@ -711,7 +710,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 for impl_item_ref in items {
                     let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
 
-                    if let Some(def_id) = impl_item.trait_item_def_id {
+                    if let AssocContainer::TraitImpl(Ok(def_id)) = impl_item.container {
                         // Pass `None` to skip deprecation warnings.
                         self.tcx.check_stability(
                             def_id,
diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs
index 1b5f0ed1429..bcc77ff849d 100644
--- a/compiler/rustc_public/src/ty.rs
+++ b/compiler/rustc_public/src/ty.rs
@@ -1612,11 +1612,7 @@ crate_def! {
 pub struct AssocItem {
     pub def_id: AssocDef,
     pub kind: AssocKind,
-    pub container: AssocItemContainer,
-
-    /// If this is an item in an impl of a trait then this is the `DefId` of
-    /// the associated item on the trait that this implements.
-    pub trait_item_def_id: Option<AssocDef>,
+    pub container: AssocContainer,
 }
 
 #[derive(Clone, PartialEq, Debug, Eq, Serialize)]
@@ -1636,9 +1632,11 @@ pub enum AssocKind {
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
-pub enum AssocItemContainer {
+pub enum AssocContainer {
+    InherentImpl,
+    /// The `AssocDef` points to the trait item being implemented.
+    TraitImpl(AssocDef),
     Trait,
-    Impl,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 207038db40d..5131611eb02 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -1076,14 +1076,21 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind {
     }
 }
 
-impl<'tcx> Stable<'tcx> for ty::AssocItemContainer {
-    type T = crate::ty::AssocItemContainer;
+impl<'tcx> Stable<'tcx> for ty::AssocContainer {
+    type T = crate::ty::AssocContainer;
 
-    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T {
-        use crate::ty::AssocItemContainer;
+    fn stable(
+        &self,
+        tables: &mut Tables<'_, BridgeTys>,
+        _: &CompilerCtxt<'_, BridgeTys>,
+    ) -> Self::T {
+        use crate::ty::AssocContainer;
         match self {
-            ty::AssocItemContainer::Trait => AssocItemContainer::Trait,
-            ty::AssocItemContainer::Impl => AssocItemContainer::Impl,
+            ty::AssocContainer::Trait => AssocContainer::Trait,
+            ty::AssocContainer::InherentImpl => AssocContainer::InherentImpl,
+            ty::AssocContainer::TraitImpl(trait_item_id) => {
+                AssocContainer::TraitImpl(tables.assoc_def(trait_item_id.unwrap()))
+            }
         }
     }
 }
@@ -1100,7 +1107,6 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
             def_id: tables.assoc_def(self.def_id),
             kind: self.kind.stable(tables, cx),
             container: self.container.stable(tables, cx),
-            trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
         }
     }
 }
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 0e566e20a12..cc8fbc18b73 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -231,6 +231,9 @@ resolve_item_was_cfg_out = the item is gated here
 resolve_label_with_similar_name_reachable =
     a label with a similar name is reachable
 
+resolve_legacy_derive_helpers = derive helper attribute is used before it is introduced
+    .label = the attribute is introduced here
+
 resolve_lending_iterator_report_error =
     associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
     .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type
@@ -260,6 +263,9 @@ resolve_macro_defined_later =
 resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments =
     macro-expanded `extern crate` items cannot shadow names passed with `--extern`
 
+resolve_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
+    .note = the macro is defined here
+
 resolve_macro_expected_found =
     expected {$expected}, found {$found} `{$macro_path}`
     .label = not {$article} {$expected}
@@ -268,6 +274,10 @@ resolve_macro_extern_deprecated =
     `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
     .help = try an outer attribute: `#[macro_use]`
 
+resolve_macro_use_deprecated =
+    applying the `#[macro_use]` attribute to an `extern crate` item is deprecated
+    .help = remove it and import macros at use sites with a `use` item instead
+
 resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
 
 resolve_macro_use_name_already_in_use =
@@ -339,6 +349,9 @@ resolve_param_in_ty_of_const_param =
 
 resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}`
 
+resolve_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope
+    .label = names from parent modules are not accessible without an explicit import
+
 resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
     .help = you can define integration tests in a directory named `tests`
 
@@ -348,6 +361,9 @@ resolve_reexport_of_crate_public =
 resolve_reexport_of_private =
     re-export of private `{$ident}`
 
+resolve_reexport_private_dependency =
+    {$kind} `{$name}` from private dependency '{$krate}' is re-exported
+
 resolve_relative_2018 =
     relative paths are not supported in visibilities in 2018 edition or later
     .suggestion = try
@@ -465,6 +481,14 @@ resolve_unreachable_label_suggestion_use_similarly_named =
 resolve_unreachable_label_with_similar_name_exists =
     a label with a similar name exists but is unreachable
 
+resolve_unused_extern_crate = unused extern crate
+    .label = unused
+    .suggestion = remove the unused `extern crate`
+
+resolve_unused_label = unused label
+
+resolve_unused_macro_use = unused `#[macro_use]` import
+
 resolve_variable_bound_with_different_mode =
     variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
     .label = bound in different ways
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 50a1ad23a54..95f979a3fed 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -169,7 +169,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
                         UNUSED_EXTERN_CRATES,
                         extern_crate.id,
                         span,
-                        BuiltinLintDiag::UnusedExternCrate {
+                        crate::errors::UnusedExternCrate {
                             span: extern_crate.span,
                             removal_span: extern_crate.span_with_attributes,
                         },
@@ -406,7 +406,7 @@ impl Resolver<'_, '_> {
                                 MACRO_USE_EXTERN_CRATE,
                                 import.root_id,
                                 import.span,
-                                BuiltinLintDiag::MacroUseDeprecated,
+                                crate::errors::MacroUseDeprecated,
                             );
                         }
                     }
@@ -427,7 +427,7 @@ impl Resolver<'_, '_> {
                         UNUSED_IMPORTS,
                         import.root_id,
                         import.span,
-                        BuiltinLintDiag::UnusedMacroUse,
+                        crate::errors::UnusedMacroUse,
                     );
                 }
                 _ => {}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 689e713ef46..236ab1f09d3 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -138,7 +138,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
                 CRATE_NODE_ID,
                 span_use,
-                BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
+                errors::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def },
             );
         }
 
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 72be94e58db..f0ea97ba8a0 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_errors::{
     Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan,
     Subdiagnostic,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Ident, Span, Symbol};
 
 use crate::late::PatternSource;
@@ -566,6 +566,22 @@ pub(crate) struct ProcMacroSameCrate {
     pub(crate) is_test: bool,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(resolve_proc_macro_derive_resolution_fallback)]
+pub(crate) struct ProcMacroDeriveResolutionFallback {
+    #[label]
+    pub span: Span,
+    pub ns_descr: &'static str,
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_macro_expanded_macro_exports_accessed_by_absolute_paths)]
+pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
+    #[note]
+    pub definition: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(resolve_imported_crate)]
 pub(crate) struct CrateImported {
@@ -1276,3 +1292,40 @@ pub(crate) struct TraitImplMismatch {
     #[label(resolve_trait_impl_mismatch_label_item)]
     pub(crate) trait_item_span: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_legacy_derive_helpers)]
+pub(crate) struct LegacyDeriveHelpers {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_unused_extern_crate)]
+pub(crate) struct UnusedExternCrate {
+    #[label]
+    pub span: Span,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
+    pub removal_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_reexport_private_dependency)]
+pub(crate) struct ReexportPrivateDependency {
+    pub name: Symbol,
+    pub kind: &'static str,
+    pub krate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_unused_label)]
+pub(crate) struct UnusedLabel;
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_unused_macro_use)]
+pub(crate) struct UnusedMacroUse;
+
+#[derive(LintDiagnostic)]
+#[diag(resolve_macro_use_deprecated)]
+#[help]
+pub(crate) struct MacroUseDeprecated;
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index bc06a227571..35051675fd8 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -4,7 +4,6 @@ use rustc_ast::{self as ast, NodeId};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_middle::bug;
-use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
@@ -520,7 +519,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
                                         lint_id,
                                         orig_ident.span,
-                                        BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
+                                        errors::ProcMacroDeriveResolutionFallback {
                                             span: orig_ident.span,
                                             ns_descr: ns.descr(),
                                             ident,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d7fc028287f..33c2c7436d1 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -720,9 +720,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         EXPORTED_PRIVATE_DEPENDENCIES,
                         binding_id,
                         binding.span,
-                        BuiltinLintDiag::ReexportPrivateDependency {
-                            kind: binding.res().descr().to_string(),
-                            name: key.ident.name.to_string(),
+                        crate::errors::ReexportPrivateDependency {
+                            name: key.ident.name,
+                            kind: binding.res().descr(),
                             krate: self.tcx.crate_name(reexported_def_id.krate),
                         },
                     );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 521fef2b9d4..4d4acc60ca8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -29,7 +29,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::ty::{DelegationFnSig, Visibility};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
-use rustc_session::lint::{self, BuiltinLintDiag};
+use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::source_map::{Spanned, respan};
 use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
@@ -5225,7 +5225,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 lint::builtin::UNUSED_LABELS,
                 *id,
                 *span,
-                BuiltinLintDiag::UnusedLabel,
+                errors::UnusedLabel,
             );
         }
     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 5fa87b4cd9b..d3e98ef839b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -979,7 +979,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             LEGACY_DERIVE_HELPERS,
                             node_id,
                             ident.span,
-                            BuiltinLintDiag::LegacyDeriveHelpers(binding.span),
+                            errors::LegacyDeriveHelpers { span: binding.span },
                         );
                     }
                 }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index d81fa062e01..577a16a0d25 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -469,8 +469,7 @@ fn implemented_method<'tcx>(
     let ancestor = if let Some(impl_id) = tcx.impl_of_assoc(instance.def_id()) {
         // Implementation in an `impl` block
         trait_ref = tcx.impl_trait_ref(impl_id)?;
-        let impl_method = tcx.associated_item(instance.def_id());
-        method_id = impl_method.trait_item_def_id?;
+        method_id = tcx.trait_item_of(instance.def_id())?;
         trait_method = tcx.associated_item(method_id);
         trait_id = trait_ref.skip_binder().def_id;
         impl_id
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 19494ffc37e..633cbc3a4ae 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -46,6 +46,8 @@ use crate::symbol::{Symbol, kw, sym};
 use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
 
 /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
+///
+/// See <https://rustc-dev-guide.rust-lang.org/macro-expansion.html> for more explanation.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct SyntaxContext(u32);
 
@@ -61,7 +63,10 @@ pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
 
 #[derive(Clone, Copy, Debug)]
 struct SyntaxContextData {
+    /// The last macro expansion in the chain.
+    /// (Here we say the most deeply nested macro expansion is the "outermost" expansion.)
     outer_expn: ExpnId,
+    /// Transparency of the last macro expansion
     outer_transparency: Transparency,
     parent: SyntaxContext,
     /// This context, but with all transparent and semi-opaque expansions filtered away.
@@ -450,11 +455,13 @@ impl HygieneData {
         self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
     }
 
+    /// See [`SyntaxContextData::outer_expn`]
     #[inline]
     fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
         self.syntax_context_data[ctxt.0 as usize].outer_expn
     }
 
+    /// The last macro expansion and its Transparency
     #[inline]
     fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
         let data = &self.syntax_context_data[ctxt.0 as usize];
@@ -900,6 +907,7 @@ impl SyntaxContext {
         HygieneData::with(|data| data.normalize_to_macro_rules(self))
     }
 
+    /// See [`SyntaxContextData::outer_expn`]
     #[inline]
     pub fn outer_expn(self) -> ExpnId {
         HygieneData::with(|data| data.outer_expn(self))
@@ -912,6 +920,7 @@ impl SyntaxContext {
         HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
     }
 
+    /// See [`HygieneData::outer_mark`]
     #[inline]
     fn outer_mark(self) -> (ExpnId, Transparency) {
         HygieneData::with(|data| data.outer_mark(self))
@@ -982,19 +991,20 @@ impl Span {
 #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct ExpnData {
     // --- The part unique to each expansion.
-    /// The kind of this expansion - macro or compiler desugaring.
     pub kind: ExpnKind,
-    /// The expansion that produced this expansion.
+    /// The expansion that contains the definition of the macro for this expansion.
     pub parent: ExpnId,
-    /// The location of the actual macro invocation or syntax sugar , e.g.
-    /// `let x = foo!();` or `if let Some(y) = x {}`
+    /// The span of the macro call which produced this expansion.
+    ///
+    /// This span will typically have a different `ExpnData` and `call_site`.
+    /// This recursively traces back through any macro calls which expanded into further
+    /// macro calls, until the "source call-site" is reached at the root SyntaxContext.
+    /// For example, if `food!()` expands to `fruit!()` which then expands to `grape`,
+    /// then the call-site of `grape` is `fruit!()` and the call-site of `fruit!()`
+    /// is `food!()`.
     ///
-    /// This may recursively refer to other macro invocations, e.g., if
-    /// `foo!()` invoked `bar!()` internally, and there was an
-    /// expression inside `bar!`; the call_site of the expression in
-    /// the expansion would point to the `bar!` invocation; that
-    /// call_site span would have its own ExpnData, with the call_site
-    /// pointing to the `foo!` invocation.
+    /// For a desugaring expansion, this is the span of the expression or node that was
+    /// desugared.
     pub call_site: Span,
     /// Used to force two `ExpnData`s to have different `Fingerprint`s.
     /// Due to macro expansion, it's possible to end up with two `ExpnId`s
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index ae6755f0764..e95b743b1ce 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -710,8 +710,8 @@ impl Span {
         if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
     }
 
-    /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
-    /// if any.
+    /// Returns the call-site span of the last macro expansion which produced this `Span`.
+    /// (see [`ExpnData::call_site`]). Returns `None` if this is not an expansion.
     pub fn parent_callsite(self) -> Option<Span> {
         let ctxt = self.ctxt();
         (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index e042ce84955..f997842a607 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -857,11 +857,11 @@ fn foo(&self) -> Self::T { String::new() }
                     && self.infcx.can_eq(param_env, assoc_ty, found)
                 {
                     let msg = match assoc_item.container {
-                        ty::AssocItemContainer::Trait => {
+                        ty::AssocContainer::Trait => {
                             "associated type defaults can't be assumed inside the \
                                             trait defining them"
                         }
-                        ty::AssocItemContainer::Impl => {
+                        ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
                             "associated type is `default` and may be overridden"
                         }
                     };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 7369134420c..518d4fe17e8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -571,13 +571,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // but right now it's not really very smart when it comes to implicit `Sized`
         // predicates and bounds on the trait itself.
 
-        let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx)
-        else {
-            return;
-        };
-        let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else {
+        let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(impl_item_def_id.to_def_id()) else {
             return;
         };
+        let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
         let trait_args = trait_ref
             .instantiate_identity()
             // Replace the explicit self type with `Self` for better suggestion rendering
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
index 8a67e4ccd45..f54ebd76cab 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
@@ -5,7 +5,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, lang_items};
-use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
+use rustc_middle::ty::{AssocContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
 use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym};
 use tracing::debug;
 
@@ -76,8 +76,9 @@ pub fn call_kind<'tcx>(
     let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
         let container_id = assoc.container_id(tcx);
         match assoc.container {
-            AssocItemContainer::Impl => tcx.trait_id_of_impl(container_id),
-            AssocItemContainer::Trait => Some(container_id),
+            AssocContainer::InherentImpl => None,
+            AssocContainer::TraitImpl(_) => tcx.trait_id_of_impl(container_id),
+            AssocContainer::Trait => Some(container_id),
         }
     });
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index cb84d583e6e..f2f840581cf 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -421,7 +421,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 })
                 | hir::Node::ImplItem(hir::ImplItem {
                     generics,
-                    trait_item_def_id: None,
+                    impl_kind: hir::ImplItemImplKind::Inherent { .. },
                     kind: hir::ImplItemKind::Fn(..),
                     ..
                 }) if finder.can_suggest_bound(generics) => {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 19eb85506b6..4d0465777dd 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -387,7 +387,7 @@ pub(crate) fn assoc_def(
     if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
         // Ensure that the impl is constrained, otherwise projection may give us
         // bad unconstrained infer vars.
-        if assoc_item.item.container == ty::AssocItemContainer::Impl
+        if let ty::AssocContainer::TraitImpl(_) = assoc_item.item.container
             && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local()
         {
             tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index e9629e31482..84f52e7fc9d 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -2,7 +2,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatorState};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, ItemKind};
+use rustc_hir::{self as hir, ImplItemImplKind, ItemKind};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -63,7 +63,7 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
     tcx.associated_items(impl_id)
         .in_definition_order()
-        .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
+        .filter_map(|item| item.trait_item_def_id().map(|trait_item| (trait_item, item.def_id)))
         .collect()
 }
 
@@ -97,12 +97,7 @@ fn associated_item_from_trait_item(
         }
     };
 
-    ty::AssocItem {
-        kind,
-        def_id: owner_id.to_def_id(),
-        trait_item_def_id: Some(owner_id.to_def_id()),
-        container: ty::AssocItemContainer::Trait,
-    }
+    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container: ty::AssocContainer::Trait }
 }
 
 fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem {
@@ -118,12 +113,13 @@ fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>
         }
     };
 
-    ty::AssocItem {
-        kind,
-        def_id: owner_id.to_def_id(),
-        trait_item_def_id: impl_item.trait_item_def_id,
-        container: ty::AssocItemContainer::Impl,
-    }
+    let container = match impl_item.impl_kind {
+        ImplItemImplKind::Inherent { .. } => ty::AssocContainer::InherentImpl,
+        ImplItemImplKind::Trait { trait_item_def_id, .. } => {
+            ty::AssocContainer::TraitImpl(trait_item_def_id)
+        }
+    };
+    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container }
 }
 struct RPITVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -190,7 +186,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
                     }
                     let did = item.owner_id.def_id.to_def_id();
                     let item = tcx.hir_impl_item(*item);
-                    let Some(trait_item_def_id) = item.trait_item_def_id else {
+                    let ImplItemImplKind::Trait {
+                        trait_item_def_id: Ok(trait_item_def_id), ..
+                    } = item.impl_kind
+                    else {
                         return Some((did, vec![]));
                     };
                     let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
@@ -256,8 +255,7 @@ fn associated_type_for_impl_trait_in_trait(
             }),
         },
         def_id,
-        trait_item_def_id: None,
-        container: ty::AssocItemContainer::Trait,
+        container: ty::AssocContainer::Trait,
     });
 
     // Copy visility of the containing function.
@@ -322,8 +320,7 @@ fn associated_type_for_impl_trait_in_impl(
             }),
         },
         def_id,
-        trait_item_def_id: Some(trait_assoc_def_id),
-        container: ty::AssocItemContainer::Impl,
+        container: ty::AssocContainer::TraitImpl(Ok(trait_assoc_def_id)),
     });
 
     // Copy visility of the containing function.
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index cdfb93c4e7d..543f6a3ccf7 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -107,7 +107,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
                 // the assumed wf types of the trait's RPITIT GAT.
                 ty::ImplTraitInTraitData::Impl { .. } => {
                     let impl_def_id = tcx.local_parent(def_id);
-                    let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap();
+                    let rpitit_def_id = tcx.trait_item_of(def_id).unwrap();
                     let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
                         tcx,
                         impl_def_id.to_def_id(),
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 4a7263d0ccd..eb3236d3006 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -245,7 +245,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
 
                         for &assoc in self.tcx.associated_items(parent).in_definition_order() {
                             trace!(?assoc);
-                            if assoc.trait_item_def_id != Some(alias_ty.def_id) {
+                            if assoc.expect_trait_impl() != Ok(alias_ty.def_id) {
                                 continue;
                             }
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index b22c326b9f2..a5987757dc3 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -88,7 +88,10 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
                 }),
             ..
         })
-        | hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+        | hir::Node::ImplItem(hir::ImplItem {
+            impl_kind: hir::ImplItemImplKind::Trait { defaultness, .. },
+            ..
+        })
         | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
         node => {
             bug!("`defaultness` called on {:?}", node);
@@ -165,7 +168,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
 
     if tcx.def_kind(def_id) == DefKind::AssocFn
         && let assoc_item = tcx.associated_item(def_id)
-        && assoc_item.container == ty::AssocItemContainer::Trait
+        && assoc_item.container == ty::AssocContainer::Trait
         && assoc_item.defaultness(tcx).has_value()
     {
         let sig = tcx.fn_sig(def_id).instantiate_identity();
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index 88ad1197777..643bd95df84 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -202,18 +202,23 @@ mod sealed {
     impl<T> Sealed for *const T {}
 }
 
-/// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
+/// Types that are valid to read using [`VaListImpl::arg`].
 ///
 /// # Safety
 ///
-/// This trait must only be implemented for types that C passes as varargs without implicit promotion.
+/// The standard library implements this trait for primitive types that are
+/// expected to have a variable argument application-binary interface (ABI) on all
+/// platforms.
 ///
-/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`]
-/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for
-/// types that are subject to this promotion rule is invalid.
+/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller
+/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively.
+/// Implementing this trait for types that are subject to this promotion rule is invalid.
 ///
 /// [`c_int`]: core::ffi::c_int
 /// [`c_double`]: core::ffi::c_double
+// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
+// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
+// to accept unsupported types in the meantime.
 pub unsafe trait VaArgSafe: sealed::Sealed {}
 
 // i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
@@ -233,7 +238,19 @@ unsafe impl<T> VaArgSafe for *mut T {}
 unsafe impl<T> VaArgSafe for *const T {}
 
 impl<'f> VaListImpl<'f> {
-    /// Advance to the next arg.
+    /// Advance to and read the next variable argument.
+    ///
+    /// # Safety
+    ///
+    /// This function is only sound to call when the next variable argument:
+    ///
+    /// - has a type that is ABI-compatible with the type `T`
+    /// - has a value that is a properly initialized value of type `T`
+    ///
+    /// Calling this function with an incompatible type, an invalid value, or when there
+    /// are no more variable arguments, is unsound.
+    ///
+    /// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html
     #[inline]
     pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
         // SAFETY: the caller must uphold the safety contract for `va_arg`.
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index e33f58197bb..f21fe0b4438 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -335,43 +335,6 @@ macro_rules! define_bignum {
                 }
                 (self, borrow)
             }
-
-            /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
-            /// remainder.
-            pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) {
-                // Stupid slow base-2 long division taken from
-                // https://en.wikipedia.org/wiki/Division_algorithm
-                // FIXME use a greater base ($ty) for the long division.
-                assert!(!d.is_zero());
-                let digitbits = <$ty>::BITS as usize;
-                for digit in &mut q.base[..] {
-                    *digit = 0;
-                }
-                for digit in &mut r.base[..] {
-                    *digit = 0;
-                }
-                r.size = d.size;
-                q.size = 1;
-                let mut q_is_zero = true;
-                let end = self.bit_length();
-                for i in (0..end).rev() {
-                    r.mul_pow2(1);
-                    r.base[0] |= self.get_bit(i) as $ty;
-                    if &*r >= d {
-                        r.sub(d);
-                        // Set bit `i` of q to 1.
-                        let digit_idx = i / digitbits;
-                        let bit_idx = i % digitbits;
-                        if q_is_zero {
-                            q.size = digit_idx + 1;
-                            q_is_zero = false;
-                        }
-                        q.base[digit_idx] |= 1 << bit_idx;
-                    }
-                }
-                debug_assert!(q.base[q.size..].iter().all(|&d| d == 0));
-                debug_assert!(r.base[r.size..].iter().all(|&d| d == 0));
-            }
         }
 
         impl crate::cmp::PartialEq for $name {
diff --git a/library/coretests/tests/fmt/builders.rs b/library/coretests/tests/fmt/builders.rs
index ba4801f5912..156eebb1e9d 100644
--- a/library/coretests/tests/fmt/builders.rs
+++ b/library/coretests/tests/fmt/builders.rs
@@ -173,6 +173,21 @@ mod debug_struct {
             format!("{Bar:#?}")
         );
     }
+
+    #[test]
+    fn test_field_with() {
+        struct Foo;
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_struct("Foo")
+                    .field_with("bar", |f| f.write_str("true"))
+                    .field_with("baz", |f| f.write_str("false"))
+                    .finish()
+            }
+        }
+
+        assert_eq!("Foo {\n    bar: true,\n    baz: false,\n}", format!("{Foo:#?}"))
+    }
 }
 
 mod debug_tuple {
diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs
index 16f116d2590..586e890befe 100644
--- a/library/coretests/tests/fmt/mod.rs
+++ b/library/coretests/tests/fmt/mod.rs
@@ -58,6 +58,36 @@ fn test_fmt_debug_of_raw_pointers() {
 }
 
 #[test]
+fn test_fmt_debug_of_mut_reference() {
+    let mut x: u32 = 0;
+
+    assert_eq!(format!("{:?}", &mut x), "0");
+}
+
+#[test]
+fn test_default_write_impls() {
+    use core::fmt::Write;
+
+    struct Buf(String);
+
+    impl Write for Buf {
+        fn write_str(&mut self, s: &str) -> core::fmt::Result {
+            self.0.write_str(s)
+        }
+    }
+
+    let mut buf = Buf(String::new());
+    buf.write_char('a').unwrap();
+
+    assert_eq!(buf.0, "a");
+
+    let mut buf = Buf(String::new());
+    buf.write_fmt(format_args!("a")).unwrap();
+
+    assert_eq!(buf.0, "a");
+}
+
+#[test]
 fn test_estimated_capacity() {
     assert_eq!(format_args!("").estimated_capacity(), 0);
     assert_eq!(format_args!("{}", { "" }).estimated_capacity(), 0);
diff --git a/library/coretests/tests/fmt/num.rs b/library/coretests/tests/fmt/num.rs
index 4c145b484dd..052b16db521 100644
--- a/library/coretests/tests/fmt/num.rs
+++ b/library/coretests/tests/fmt/num.rs
@@ -323,3 +323,9 @@ fn test_format_debug_hex() {
     assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
     assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
 }
+
+#[test]
+#[should_panic = "Formatting argument out of range"]
+fn test_rt_width_too_long() {
+    let _ = format!("Hello {:width$}!", "x", width = u16::MAX as usize + 1);
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index a246c806140..5c519f3a499 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -33,6 +33,7 @@
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
 #![feature(cstr_display)]
+#![feature(debug_closure_helpers)]
 #![feature(dec2flt)]
 #![feature(drop_guard)]
 #![feature(duration_constants)]
diff --git a/library/coretests/tests/num/bignum.rs b/library/coretests/tests/num/bignum.rs
index f213fd5366c..6dfa496e018 100644
--- a/library/coretests/tests/num/bignum.rs
+++ b/library/coretests/tests/num/bignum.rs
@@ -168,25 +168,6 @@ fn test_div_rem_small() {
 }
 
 #[test]
-fn test_div_rem() {
-    fn div_rem(n: u64, d: u64) -> (Big, Big) {
-        let mut q = Big::from_small(42);
-        let mut r = Big::from_small(42);
-        Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r);
-        (q, r)
-    }
-    assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0)));
-    assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1)));
-    assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1)));
-    assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0)));
-    assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4)));
-    assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25)));
-    assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0)));
-    assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee)));
-    assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0)));
-}
-
-#[test]
 fn test_is_zero() {
     assert!(Big::from_small(0).is_zero());
     assert!(!Big::from_small(3).is_zero());
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs
index f8774833d0a..4d5138d539b 100644
--- a/library/coretests/tests/ptr.rs
+++ b/library/coretests/tests/ptr.rs
@@ -490,6 +490,14 @@ fn is_aligned() {
 }
 
 #[test]
+#[should_panic = "is_aligned_to: align is not a power-of-two"]
+fn invalid_is_aligned() {
+    let data = 42;
+    let ptr: *const i32 = &data;
+    assert!(ptr.is_aligned_to(3));
+}
+
+#[test]
 fn offset_from() {
     let mut a = [0; 5];
     let ptr1: *mut i32 = &mut a[1];
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 1c55824ab90..7ff4af8ede8 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1257,6 +1257,108 @@ mod ref_keyword {}
 /// [`async`]: ../std/keyword.async.html
 mod return_keyword {}
 
+#[doc(keyword = "become")]
+//
+/// Perform a tail-call of a function.
+///
+/// <div class="warning">
+///
+/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly.
+/// </div>
+///
+/// When tail calling a function, instead of its stack frame being added to the
+/// stack, the stack frame of the caller is directly replaced with the callee's.
+/// This means that as long as a loop in a call graph only uses tail calls, the
+/// stack growth will be bounded.
+///
+/// This is useful for writing functional-style code (since it prevents recursion
+/// from exhausting resources) or for code optimization (since a tail call
+/// *might* be cheaper than a normal call, tail calls can be used in a similar
+/// manner to computed goto).
+///
+/// Example of using `become` to implement functional-style `fold`:
+/// ```
+/// #![feature(explicit_tail_calls)]
+/// #![expect(incomplete_features)]
+///
+/// fn fold<T: Copy, S>(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S {
+///     match slice {
+///         // without `become`, on big inputs this could easily overflow the
+///         // stack. using a tail call guarantees that the stack will not grow unboundedly
+///         [first, rest @ ..] => become fold(rest, f(init, *first), f),
+///         [] => init,
+///     }
+/// }
+/// ```
+///
+/// Compilers can already perform "tail call optimization" -- they can replace normal
+/// calls with tail calls, although there are no guarantees that this will be done.
+/// However, to perform TCO, the call needs to be the last thing that happens
+/// in the functions and be returned from it. This requirement is often broken
+/// by drop code for locals, which is run after computing the return expression:
+///
+/// ```
+/// fn example() {
+///     let string = "meow".to_owned();
+///     println!("{string}");
+///     return help(); // this is *not* the last thing that happens in `example`...
+/// }
+///
+/// // ... because it is desugared to this:
+/// fn example_desugared() {
+///     let string = "meow".to_owned();
+///     println!("{string}");
+///     let tmp = help();
+///     drop(string);
+///     return tmp;
+/// }
+///
+/// fn help() {}
+/// ```
+///
+/// For this reason, `become` also changes the drop order, such that locals are
+/// dropped *before* evaluating the call.
+///
+/// In order to guarantee that the compiler can perform a tail call, `become`
+/// currently has these requirements:
+/// 1. callee and caller must have the same ABI, arguments, and return type
+/// 2. callee and caller must not have varargs
+/// 3. caller must not be marked with `#[track_caller]`
+///    - callee is allowed to be marked with `#[track_caller]` as otherwise
+///      adding `#[track_caller]` would be a breaking change. if callee is
+///      marked with `#[track_caller]` a tail call is not guaranteed.
+/// 4. callee and caller cannot be a closure
+///    (unless it's coerced to a function pointer)
+///
+/// It is possible to tail-call a function pointer:
+/// ```
+/// #![feature(explicit_tail_calls)]
+/// #![expect(incomplete_features)]
+///
+/// #[derive(Copy, Clone)]
+/// enum Inst { Inc, Dec }
+///
+/// fn dispatch(stream: &[Inst], state: u32) -> u32 {
+///     const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement];
+///     match stream {
+///         [inst, rest @ ..] => become TABLE[*inst as usize](rest, state),
+///         [] => state,
+///     }
+/// }
+///
+/// fn increment(stream: &[Inst], state: u32) -> u32 {
+///     become dispatch(stream, state + 1)
+/// }
+///
+/// fn decrement(stream: &[Inst], state: u32) -> u32 {
+///     become dispatch(stream, state - 1)
+/// }
+///
+/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc];
+/// assert_eq!(dispatch(program, 0), 2);
+/// ```
+mod become_keyword {}
+
 #[doc(keyword = "self")]
 //
 /// The receiver of a method, or the current module.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5725816c600..33e3bf0c085 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -284,7 +284,6 @@
 #![feature(core_float_math)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
-#![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(doc_masked)]
@@ -332,11 +331,7 @@
 #![feature(cfg_select)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
-#![feature(const_cmp)]
 #![feature(const_convert)]
-#![feature(const_ops)]
-#![feature(const_option_ops)]
-#![feature(const_try)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(drop_guard)]
diff --git a/library/std/src/sync/nonpoison/condvar.rs b/library/std/src/sync/nonpoison/condvar.rs
index 49afdd87818..994fc6816a0 100644
--- a/library/std/src/sync/nonpoison/condvar.rs
+++ b/library/std/src/sync/nonpoison/condvar.rs
@@ -198,11 +198,10 @@ impl Condvar {
     /// the system time. This function is susceptible to spurious wakeups.
     /// Condition variables normally have a boolean predicate associated with
     /// them, and the predicate must always be checked each time this function
-    /// returns to protect against spurious wakeups. Additionally, it is
-    /// typically desirable for the timeout to not exceed some duration in
-    /// spite of spurious wakes, thus the sleep-duration is decremented by the
-    /// amount slept. Alternatively, use the `wait_timeout_while` method
-    /// to wait with a timeout while a predicate is true.
+    /// returns to protect against spurious wakeups.  Furthermore, since the timeout
+    /// is given relative to the moment this function is called, it needs to be adjusted
+    /// when this function is called in a loop. The [`wait_timeout_while`] method
+    /// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
     ///
     /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
     /// known to have elapsed.
diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs
index 5dc2b510f3a..de625a6cc5f 100644
--- a/library/std/src/sync/poison/condvar.rs
+++ b/library/std/src/sync/poison/condvar.rs
@@ -269,11 +269,10 @@ impl Condvar {
     /// the system time. This function is susceptible to spurious wakeups.
     /// Condition variables normally have a boolean predicate associated with
     /// them, and the predicate must always be checked each time this function
-    /// returns to protect against spurious wakeups. Additionally, it is
-    /// typically desirable for the timeout to not exceed some duration in
-    /// spite of spurious wakes, thus the sleep-duration is decremented by the
-    /// amount slept. Alternatively, use the `wait_timeout_while` method
-    /// to wait with a timeout while a predicate is true.
+    /// returns to protect against spurious wakeups. Furthermore, since the timeout
+    /// is given relative to the moment this function is called, it needs to be adjusted
+    /// when this function is called in a loop. The [`wait_timeout_while`] method
+    /// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
     ///
     /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
     /// known to have elapsed.
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index 89a427ab88b..f76a5f96c87 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -25,15 +25,8 @@ impl Timespec {
         Timespec { t: timespec { tv_sec, tv_nsec } }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        // FIXME: const PartialOrd
-        let mut cmp = self.t.tv_sec - other.t.tv_sec;
-        if cmp == 0 {
-            cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64;
-        }
-
-        if cmp >= 0 {
+    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        if self >= other {
             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                 Duration::new(
                     (self.t.tv_sec - other.t.tv_sec) as u64,
@@ -53,22 +46,20 @@ impl Timespec {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
-        if nsec >= NSEC_PER_SEC as u32 {
-            nsec -= NSEC_PER_SEC as u32;
+        let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
+        if nsec >= NSEC_PER_SEC.try_into().unwrap() {
+            nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
             secs = secs.checked_add(1)?;
         }
         Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
@@ -222,18 +213,15 @@ impl SystemTime {
         SystemTime(time)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.0.sub_timespec(&other.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add_duration(other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub_duration(other)?))
     }
 }
diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs
index 603dae952ab..db4cf2804bf 100644
--- a/library/std/src/sys/pal/sgx/time.rs
+++ b/library/std/src/sys/pal/sgx/time.rs
@@ -32,22 +32,15 @@ impl SystemTime {
         SystemTime(usercalls::insecure_time())
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs
index e35e60df1a0..c39d715c6a6 100644
--- a/library/std/src/sys/pal/solid/time.rs
+++ b/library/std/src/sys/pal/solid/time.rs
@@ -39,8 +39,7 @@ impl SystemTime {
         Self(t)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         if self.0 >= other.0 {
             Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
         } else {
@@ -48,13 +47,11 @@ impl SystemTime {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
     }
 }
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index 36ce3f7ef96..c6636626fd5 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -80,32 +80,19 @@ impl SystemTime {
             .unwrap_or_else(|| panic!("time not implemented on this platform"))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        let temp = self.0.checked_add(*other)?;
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        let temp = Self(self.0.checked_add(*other)?);
 
         // Check if can be represented in UEFI
-        // FIXME: const PartialOrd
-        let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs();
-        if cmp == 0 {
-            cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64;
-        }
-
-        if cmp <= 0 { Some(SystemTime(temp)) } else { None }
+        if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(*other)?))
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        self.0.checked_sub(*other).map(Self)
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index 328fe0bc960..bd7f74fea6a 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -38,18 +38,15 @@ impl SystemTime {
         SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.t.sub_timespec(&other.t)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime { t: self.t.checked_add_duration(other)? })
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime { t: self.t.checked_sub_duration(other)? })
     }
 }
@@ -136,15 +133,8 @@ impl Timespec {
         Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap()
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        // FIXME: const PartialOrd
-        let mut cmp = self.tv_sec - other.tv_sec;
-        if cmp == 0 {
-            cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64;
-        }
-
-        if cmp >= 0 {
+    pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        if self >= other {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
             // to optimize it into a branchless form (see also #75545):
             //
@@ -179,8 +169,7 @@ impl Timespec {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
@@ -190,11 +179,10 @@ impl Timespec {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
+        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
@@ -203,7 +191,7 @@ impl Timespec {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
+        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
     }
 
     #[allow(dead_code)]
diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs
index 0c387917044..6d67b538a96 100644
--- a/library/std/src/sys/pal/unsupported/time.rs
+++ b/library/std/src/sys/pal/unsupported/time.rs
@@ -31,22 +31,15 @@ impl SystemTime {
         panic!("time not implemented on this platform")
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/wasip1/time.rs b/library/std/src/sys/pal/wasip1/time.rs
index 892661b312b..0d8d0b59ac1 100644
--- a/library/std/src/sys/pal/wasip1/time.rs
+++ b/library/std/src/sys/pal/wasip1/time.rs
@@ -43,34 +43,23 @@ impl SystemTime {
         SystemTime(current_time(wasi::CLOCKID_REALTIME))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
+    pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
         SystemTime(Duration::from_nanos(ts))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
-        // FIXME: const TryInto
-        let ns = self.0.as_nanos();
-        if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
+    pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
+        self.0.as_nanos().try_into().ok()
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs
index 980070e7b85..43489183994 100644
--- a/library/std/src/sys/pal/wasip2/time.rs
+++ b/library/std/src/sys/pal/wasip2/time.rs
@@ -36,34 +36,23 @@ impl SystemTime {
         SystemTime(Duration::new(now.seconds, now.nanoseconds))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
+    pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
         SystemTime(Duration::from_nanos(ts))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
-        // FIXME: const TryInto
-        let ns = self.0.as_nanos();
-        if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
+    pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
+        self.0.as_nanos().try_into().ok()
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index f8f9a9fd818..0d31b80e56a 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -72,8 +72,7 @@ impl SystemTime {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    const fn from_intervals(intervals: i64) -> SystemTime {
+    fn from_intervals(intervals: i64) -> SystemTime {
         SystemTime {
             t: c::FILETIME {
                 dwLowDateTime: intervals as u32,
@@ -82,13 +81,11 @@ impl SystemTime {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    const fn intervals(&self) -> i64 {
+    fn intervals(&self) -> i64 {
         (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         let me = self.intervals();
         let other = other.intervals();
         if me >= other {
@@ -98,14 +95,12 @@ impl SystemTime {
         }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
         Some(SystemTime::from_intervals(intervals))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
         Some(SystemTime::from_intervals(intervals))
     }
@@ -155,18 +150,15 @@ impl Hash for SystemTime {
     }
 }
 
-#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-const fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
-    // FIXME: const TryInto
-    let secs = dur
-        .as_secs()
+fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
+    dur.as_secs()
         .checked_mul(INTERVALS_PER_SEC)?
-        .checked_add(dur.subsec_nanos() as u64 / 100)?;
-    if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None }
+        .checked_add(dur.subsec_nanos() as u64 / 100)?
+        .try_into()
+        .ok()
 }
 
-#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-const fn intervals2dur(intervals: u64) -> Duration {
+fn intervals2dur(intervals: u64) -> Duration {
     Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
 }
 
diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs
index d737416436e..ae8be81c0b7 100644
--- a/library/std/src/sys/pal/xous/time.rs
+++ b/library/std/src/sys/pal/xous/time.rs
@@ -43,22 +43,15 @@ impl SystemTime {
         SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) }
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        // FIXME: ok_or_else with const closures
-        match self.0.checked_sub(other.0) {
-            Some(duration) => Ok(duration),
-            None => Err(other.0 - self.0),
-        }
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 84fbb4c2fe4..31187adb6fe 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -551,13 +551,8 @@ impl SystemTime {
     /// println!("{difference:?}");
     /// ```
     #[stable(feature = "time2", since = "1.8.0")]
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
-        // FIXME: map_err in const
-        match self.0.sub_time(&earlier.0) {
-            Ok(time) => Ok(time),
-            Err(err) => Err(SystemTimeError(err)),
-        }
+    pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
+        self.0.sub_time(&earlier.0).map_err(SystemTimeError)
     }
 
     /// Returns the difference from this system time to the
@@ -594,8 +589,7 @@ impl SystemTime {
     /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
     /// otherwise.
     #[stable(feature = "time_checked_add", since = "1.34.0")]
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
+    pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
         self.0.checked_add_duration(&duration).map(SystemTime)
     }
 
@@ -603,15 +597,13 @@ impl SystemTime {
     /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
     /// otherwise.
     #[stable(feature = "time_checked_add", since = "1.34.0")]
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
+    pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
         self.0.checked_sub_duration(&duration).map(SystemTime)
     }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
-#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
-impl const Add<Duration> for SystemTime {
+impl Add<Duration> for SystemTime {
     type Output = SystemTime;
 
     /// # Panics
@@ -624,16 +616,14 @@ impl const Add<Duration> for SystemTime {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
-impl const AddAssign<Duration> for SystemTime {
+impl AddAssign<Duration> for SystemTime {
     fn add_assign(&mut self, other: Duration) {
         *self = *self + other;
     }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
-#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
-impl const Sub<Duration> for SystemTime {
+impl Sub<Duration> for SystemTime {
     type Output = SystemTime;
 
     fn sub(self, dur: Duration) -> SystemTime {
@@ -642,8 +632,7 @@ impl const Sub<Duration> for SystemTime {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
-impl const SubAssign<Duration> for SystemTime {
+impl SubAssign<Duration> for SystemTime {
     fn sub_assign(&mut self, other: Duration) {
         *self = *self - other;
     }
@@ -710,8 +699,7 @@ impl SystemTimeError {
     /// ```
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
-    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
-    pub const fn duration(&self) -> Duration {
+    pub fn duration(&self) -> Duration {
         self.0
     }
 }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 04cf63f1c6d..68202500d97 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -287,7 +287,7 @@ than building it.
 
             if !has_target {
                 panic!(
-                    "No such target exists in the target list,\n\
+                    "{target_str}: No such target exists in the target list,\n\
                      make sure to correctly specify the location \
                      of the JSON specification file \
                      for custom targets!\n\
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 8e378e53e51..e4bf33dd8a0 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -48,6 +48,7 @@
     - [\*-apple-visionos](platform-support/apple-visionos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
+    - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md)
     - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
     - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md)
     - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
@@ -55,7 +56,9 @@
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
       - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
       - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
-      - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
+      - [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md)
+      - [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md)
+      - [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md)
       - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md)
       - [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md)
       - [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md)
diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md
index 00add2651ae..4caeaa106b4 100644
--- a/src/doc/rustc/src/check-cfg.md
+++ b/src/doc/rustc/src/check-cfg.md
@@ -134,7 +134,7 @@ As of `2025-01-02T`, the list of known names is as follows:
  - `unix`
  - `windows`
 
-> Starting with 1.85.0, the `test` cfg is consider to be a "userspace" config
+> Starting with 1.85.0, the `test` cfg is considered to be a "userspace" config
 > despite being also set by `rustc` and should be managed by the build system itself.
 
 Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())`
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 9ad9cb5b526..e5e46f72637 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -149,22 +149,22 @@ target | std | notes
 [`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
-`aarch64-unknown-none` | * | Bare ARM64, hardfloat
-`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
+[`aarch64-unknown-none`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, hardfloat
+[`aarch64-unknown-none-softfloat`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, softfloat
 [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI
 [`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
 `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
 `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
-[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
-[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
+[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
+[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
 [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
 `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
 `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3
 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat
-[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
+[`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A
 [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
 [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
 `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87]
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md
new file mode 100644
index 00000000000..7e18e8c157f
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md
@@ -0,0 +1,78 @@
+# `aarch64-unknown-none` and `aarch64-unknown-none-softfloat`
+
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
+
+Bare-metal targets for CPUs in the Armv8-A architecture family, running in AArch64 mode.
+
+For the AArch32 mode carried over from Armv7-A, see
+[`armv7a-none-eabi`](armv7a-none-eabi.md) instead.
+
+Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus].
+
+[aarch64-cpus]: https://en.wikipedia.org/wiki/Comparison_of_ARM_processors#ARMv8-A
+
+## Target maintainers
+
+[Rust Embedded Devices Working Group Arm Team]
+
+[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+
+## Target CPU and Target Feature options
+
+All AArch64 processors include an FPU. The difference between the `-none` and
+`-none-softfloat` targets is whether the FPU is used for passing function arguments.
+You may prefer the `-softfloat` target when writing a kernel or interfacing with
+pre-compiled binaries that use the soft-float ABI.
+
+When using the hardfloat targets, the minimum floating-point features assumed
+are those of the `fp-armv8`, which excludes NEON SIMD support. If your
+processor supports a different set of floating-point features than the default
+expectations of `fp-armv8`, then these should also be enabled or disabled as
+needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or
+LLVM) that you have a specific model of Arm processor, using the
+[`-Ctarget-cpu`][target-cpu] option. Doing so may change the default set of
+target-features enabled.
+
+[target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu
+[target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature
+
+## Requirements
+
+These targets are cross-compiled and use static linking.
+
+By default, the `lld` linker included with Rust will be used; however, you may
+want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux
+from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's
+package manager. To use it, add the following to your `.cargo/config.toml`:
+
+```toml
+[target.aarch64-unknown-none]
+linker = "aarch64-none-elf-ld"
+```
+
+The GNU linker can also be used by specifying `aarch64-none-elf-gcc` as the
+linker. This is needed when using GCC's link time optimization.
+
+These targets don't provide a linker script, so you'll need to bring your own
+according to the specific device you are using. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+## Cross-compilation toolchains and C code
+
+This target supports C code compiled with the `aarch64-none-elf` target
+triple and a suitable `-march` or `-mcpu` flag.
+
+## Start-up and Low-Level Code
+
+The [Rust Embedded Devices Working Group Arm Team] maintain the
+[`aarch64-cpu`] crate, which may be useful for writing bare-metal code using
+this target.
+
+The *TrustedFirmware* group also maintain [Rust crates for this
+target](https://github.com/ArmFirmwareCrates).
+
+[`aarch64-cpu`]: https://docs.rs/aarch64-cpu
diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md
index 9732df4be7f..aaa80e42971 100644
--- a/src/doc/rustc/src/platform-support/arm-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md
@@ -12,10 +12,10 @@ their own document.
 ### Tier 2 Target List
 
 - Arm A-Profile Architectures
-  - `armv7a-none-eabi`
+  - [`armv7a-none-eabi`](armv7a-none-eabi.md)
 - Arm R-Profile Architectures
   - [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md)
-  - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armv7r-none-eabi.md)
+  - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armebv7r-none-eabi.md)
 - Arm M-Profile Architectures
   - [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md)
   - [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md)
@@ -28,7 +28,7 @@ their own document.
 ### Tier 3 Target List
 
 - Arm A-Profile Architectures
-  - `armv7a-none-eabihf`
+  - [`armv7a-none-eabihf`](armv7a-none-eabi.md)
 - Arm R-Profile Architectures
   - [`armv8r-none-eabihf`](armv8r-none-eabihf.md)
 - Arm M-Profile Architectures
diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
new file mode 100644
index 00000000000..3e90319c373
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
@@ -0,0 +1,55 @@
+# `armebv7r-none-eabi` and `armebv7r-none-eabihf`
+
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
+
+Bare-metal target for CPUs in the Armv7-R architecture family running in Big
+Endian mode. These processors support dual ARM/Thumb mode, with ARM mode as
+the default.
+
+**NOTE:** You should almost always prefer the [little-endian
+versions](armv7r-none-eabi.md) of these target. Big Endian Arm systems are
+highly unusual.
+
+Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
+[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R
+
+## Target maintainers
+
+[@chrisnc](https://github.com/chrisnc)
+
+## Requirements
+
+Note that some variants of the Cortex-R have both big-endian instructions and
+data. This configuration is known as BE-32, while data-only big-endianness is
+known as BE-8. To build programs for BE-32 processors, the GNU linker must be
+used with the `-mbe32` option. See [ARM Cortex-R Series Programmer's Guide:
+Endianness][endianness] for more details about different endian modes.
+
+When using the hardfloat targets, the minimum floating-point features assumed
+are those of the `vfpv3-d16`, which includes single- and double-precision, with
+16 double-precision registers. This floating-point unit appears in Cortex-R4F
+and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp]
+for more details on the possible FPU variants.
+
+If your processor supports a different set of floating-point features than the
+default expectations of `vfpv3-d16`, then these should also be enabled or
+disabled as needed with `-C target-feature=(+/-)`.
+
+[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness
+
+[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
+
+## Start-up and Low-Level Code
+
+The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
+and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code
+using this target. Those crates include several examples which run in QEMU and
+build using these targets.
+
+[`cortex-ar`]: https://docs.rs/cortex-ar
+[`cortex-r-rt`]: https://docs.rs/cortex-r-rt
diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
index 56f919e2a12..c6d88762fb1 100644
--- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
@@ -1,6 +1,7 @@
 # armv4t-none-eabi / thumbv4t-none-eabi
 
-Tier 3
+* **Tier:  3**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 These two targets are part of the [`arm-none-eabi`](arm-none-eabi.md) target
 group, and all the information there applies.
diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
index 22287972b7e..e9f34d4ede8 100644
--- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
@@ -1,6 +1,7 @@
 # `armv5te-none-eabi`
 
-**Tier: 3**
+* **Tier: 3**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for any cpu in the Armv5TE architecture family, supporting
 ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code
diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md
new file mode 100644
index 00000000000..3dadda86a5f
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md
@@ -0,0 +1,70 @@
+# `armv7a-none-eabi` and `armv7a-none-eabihf`
+
+* **Tier: 2** for `armv7a-none-eabi`
+* **Tier: 3** for `armv7a-none-eabihf`
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
+
+Bare-metal target for CPUs in the Armv7-A architecture family, supporting
+dual ARM/Thumb mode, with ARM mode as the default.
+
+Note, this is for processors running in AArch32 mode. For the AArch64 mode
+added in Armv8-A, see [`aarch64-unknown-none`](aarch64-unknown-none.md) instead.
+
+Processors in this family include the [Arm Cortex-A5, 8, 32, etc][cortex-a].
+
+See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
+`arm-none-eabi` targets.
+
+[cortex-a]: https://en.wikipedia.org/wiki/ARM_Cortex-A
+
+## Target maintainers
+
+[Rust Embedded Devices Working Group Arm Team]
+
+[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+
+## Requirements
+
+Almost all Armv7-A processors include an FPU (a VFPv3 or a VFPv4). The
+difference between the `-eabi` and `-eabihf` targets is whether the FPU is
+used for passing function arguments. You may prefer the `-eabi` soft-float
+target when the processor does not have a floating point unit or the compiled
+code should not use the floating point unit.
+
+When using the hardfloat targets, the minimum floating-point features assumed
+are those of the VFPv3-D16, which includes single- and double-precision, with
+16 double-precision registers. This floating-point unit appears in Cortex-A8
+and Cortex-A9 processors. See [VFP in the Cortex-A processors][vfp] for more
+details on the possible FPU variants.
+
+If your processor supports a different set of floating-point features than the
+default expectations of VFPv3-D16, then these should also be enabled or
+disabled as needed with `-C target-feature=(+/-)`.
+
+In general, the following four combinations are possible:
+
+- VFPv3-D16, target feature `+vfp3` and `-d32`
+- VFPv3-D32, target feature `+vfp3` and `+d32`
+- VFPv4-D16, target feature `+vfp4` and `-d32`
+- VFPv4-D32, target feature `+vfp4` and `+d32`
+
+An Armv7-A processor may optionally include a NEON hardware unit which
+provides Single Instruction Multiple Data (SIMD) operations. The
+implementation of this unit implies VFPv3-D32. The target feature `+neon` may
+be added to inform the compiler about the availability of NEON.
+
+You can refer to the [arm-none-eabi](arm-none-eabi.md) documentation for a
+generic guide on target feature and target CPU specification and how to enable
+and disable them via `.cargo/config.toml` file.
+
+[vfp]: https://developer.arm.com/documentation/den0013/0400/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/ARM-VFP
+
+## Start-up and Low-Level Code
+
+The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
+and [`cortex-a-rt`] crates, which may be useful for writing bare-metal code
+using this target. The [`cortex-ar` repository](https://github.com/rust-embedded/cortex-ar)
+includes several examples which run in QEMU and build using these targets.
+
+[`cortex-ar`]: https://docs.rs/cortex-ar
+[`cortex-a-rt`]: https://docs.rs/cortex-a-rt
diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
index 88b2689dcf0..c1252b4a4bf 100644
--- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
@@ -1,14 +1,13 @@
-# `arm(eb)?v7r-none-eabi(hf)?`
+# `armv7r-none-eabi` and `armv7r-none-eabihf`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Armv7-R architecture family, supporting
 dual ARM/Thumb mode, with ARM mode as the default.
 
 Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
 
-The `eb` versions of this target generate code for big-endian processors.
-
 See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 `arm-none-eabi` targets.
 
@@ -17,15 +16,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 ## Target maintainers
 
 [@chrisnc](https://github.com/chrisnc)
+[Rust Embedded Devices Working Group Arm Team]
 
-## Requirements
+[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
 
-When using the big-endian version of this target, note that some variants of
-the Cortex-R have both big-endian instructions and data. This configuration is
-known as BE-32, while data-only big-endianness is known as BE-8. To build
-programs for BE-32 processors, the GNU linker must be used with the `-mbe32`
-option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness]
-for more details about different endian modes.
+## Requirements
 
 When using the hardfloat targets, the minimum floating-point features assumed
 are those of the `vfpv3-d16`, which includes single- and double-precision, with
@@ -41,7 +36,12 @@ disabled as needed with `-C target-feature=(+/-)`.
 
 [vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
 
-## Cross-compilation toolchains and C code
+## Start-up and Low-Level Code
+
+The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
+and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code
+using this target. Those crates include several examples which run in QEMU and
+build using these targets.
 
-This target supports C code compiled with the `arm-none-eabi` target triple and
-`-march=armv7-r` or a suitable `-mcpu` flag.
+[`cortex-ar`]: https://docs.rs/cortex-ar
+[`cortex-r-rt`]: https://docs.rs/cortex-r-rt
diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
index 569d8802ebe..0d5a36c3ee2 100644
--- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
+++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
@@ -1,6 +1,7 @@
 # `armv8r-none-eabihf`
 
-**Tier: 3**
+* **Tier: 3**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Armv8-R architecture family, supporting
 dual ARM/Thumb mode, with ARM mode as the default.
@@ -17,6 +18,9 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 ## Target maintainers
 
 [@chrisnc](https://github.com/chrisnc)
+[Rust Embedded Devices Working Group Arm Team]
+
+[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
 
 ## Requirements
 
@@ -34,7 +38,14 @@ Technical Reference Manual for more details.
 
 [fpu]: https://developer.arm.com/documentation/100026/0104/Advanced-SIMD-and-floating-point-support/About-the-Advanced-SIMD-and-floating-point-support
 
-## Cross-compilation toolchains and C code
-
-This target supports C code compiled with the `arm-none-eabi` target triple and
-`-march=armv8-r` or a suitable `-mcpu` flag.
+### Table of supported CPUs for `armv8r-none-eabihf`
+
+| CPU         | FPU | Neon | Target CPU       | Target Features    |
+|:----------- | --- |:---- |:---------------- |:------------------ |
+| Any         | SP  | No   | None             | None               |
+| Cortex-R52  | SP  | No   | `cortex-r52`     | `-fp64,-d32,-neon` |
+| Cortex-R52  | DP  | No   | `cortex-r52`     | `-neon`            |
+| Cortex-R52  | DP  | Yes  | `cortex-r52`     | None               |
+| Cortex-R52+ | SP  | No   | `cortex-r52plus` | `-fp64,-d32,-neon` |
+| Cortex-R52+ | DP  | No   | `cortex-r52plus` | `-neon`            |
+| Cortex-R52+ | DP  | Yes  | `cortex-r52plus` | None               |
diff --git a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md
index 746b8443547..d4bd0b0945a 100644
--- a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md
@@ -1,6 +1,7 @@
 # `thumbv6m-none-eabi`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the [Armv6-M] architecture family, supporting a
 subset of the [T32 ISA][t32-isa].
@@ -26,7 +27,7 @@ only option because there is no FPU support in [Armv6-M].
 
 ## Target maintainers
 
-* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
index 12e28265678..98dcf9bd396 100644
--- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
@@ -1,6 +1,7 @@
 # `thumbv7em-none-eabi` and `thumbv7em-none-eabihf`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the [Armv7E-M] architecture family, supporting a
 subset of the [T32 ISA][t32-isa].
@@ -21,7 +22,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
index 03324b341d0..d8f3970c8bf 100644
--- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
@@ -1,6 +1,7 @@
 # `thumbv7m-none-eabi`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the [Armv7-M] architecture family, supporting a
 subset of the [T32 ISA][t32-isa].
@@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv7-M].
 
 ## Target maintainers
 
-* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
index 4a92e856466..b16d450275d 100644
--- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
@@ -1,6 +1,7 @@
 # `thumbv8m.base-none-eabi`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Baseline [Armv8-M] architecture family,
 supporting a subset of the [T32 ISA][t32-isa].
@@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv8-M] Baseline.
 
 ## Target maintainers
 
-* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
index 9f85d08fa0a..a2d515d07ea 100644
--- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
@@ -1,6 +1,7 @@
 # `thumbv8m.main-none-eabi` and `thumbv8m.main-none-eabihf`
 
-**Tier: 2**
+* **Tier: 2**
+* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Mainline [Armv8-M] architecture family,
 supporting a subset of the [T32 ISA][t32-isa].
@@ -25,7 +26,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
 
 ## Target CPU and Target Feature options
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 93932936a2e..5ccacafea01 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1256,7 +1256,10 @@ pub(crate) fn clean_impl_item<'tcx>(
             })),
             hir::ImplItemKind::Fn(ref sig, body) => {
                 let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body));
-                let defaultness = cx.tcx.defaultness(impl_.owner_id);
+                let defaultness = match impl_.impl_kind {
+                    hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
+                    hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
+                };
                 MethodItem(m, Some(defaultness))
             }
             hir::ImplItemKind::Type(hir_ty) => {
@@ -1295,12 +1298,14 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
             simplify::move_bounds_to_generic_parameters(&mut generics);
 
             match assoc_item.container {
-                ty::AssocItemContainer::Impl => ImplAssocConstItem(Box::new(Constant {
-                    generics,
-                    kind: ConstantKind::Extern { def_id: assoc_item.def_id },
-                    type_: ty,
-                })),
-                ty::AssocItemContainer::Trait => {
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
+                    ImplAssocConstItem(Box::new(Constant {
+                        generics,
+                        kind: ConstantKind::Extern { def_id: assoc_item.def_id },
+                        type_: ty,
+                    }))
+                }
+                ty::AssocContainer::Trait => {
                     if tcx.defaultness(assoc_item.def_id).has_value() {
                         ProvidedAssocConstItem(Box::new(Constant {
                             generics,
@@ -1318,10 +1323,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
 
             if has_self {
                 let self_ty = match assoc_item.container {
-                    ty::AssocItemContainer::Impl => {
+                    ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
                         tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
                     }
-                    ty::AssocItemContainer::Trait => tcx.types.self_param,
+                    ty::AssocContainer::Trait => tcx.types.self_param,
                 };
                 let self_param_ty =
                     tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
@@ -1338,13 +1343,13 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
             }
 
             let provided = match assoc_item.container {
-                ty::AssocItemContainer::Impl => true,
-                ty::AssocItemContainer::Trait => assoc_item.defaultness(tcx).has_value(),
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
+                ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
             };
             if provided {
                 let defaultness = match assoc_item.container {
-                    ty::AssocItemContainer::Impl => Some(assoc_item.defaultness(tcx)),
-                    ty::AssocItemContainer::Trait => None,
+                    ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)),
+                    ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None,
                 };
                 MethodItem(item, defaultness)
             } else {
@@ -1375,7 +1380,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
             }
 
             let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
-            if let ty::AssocItemContainer::Trait = assoc_item.container {
+            if let ty::AssocContainer::Trait = assoc_item.container {
                 let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied();
                 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
             }
@@ -1386,7 +1391,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
             );
             simplify::move_bounds_to_generic_parameters(&mut generics);
 
-            if let ty::AssocItemContainer::Trait = assoc_item.container {
+            if let ty::AssocContainer::Trait = assoc_item.container {
                 // Move bounds that are (likely) directly attached to the associated type
                 // from the where-clause to the associated type.
                 // There is no guarantee that this is what the user actually wrote but we have
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index dcd67cb7ebc..bd3f4e9a6f2 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -690,16 +690,13 @@ impl Item {
                 // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent
                 // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we
                 // won't be printing correct syntax plus the syntax is unstable.
-                match tcx.opt_associated_item(def_id) {
-                    Some(ty::AssocItem {
-                        container: ty::AssocItemContainer::Impl,
-                        trait_item_def_id: Some(_),
-                        ..
-                    })
-                    | Some(ty::AssocItem { container: ty::AssocItemContainer::Trait, .. }) => {
-                        hir::Constness::NotConst
-                    }
-                    None | Some(_) => hir::Constness::Const,
+                if let Some(assoc) = tcx.opt_associated_item(def_id)
+                    && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
+                        assoc.container
+                {
+                    hir::Constness::NotConst
+                } else {
+                    hir::Constness::Const
                 }
             } else {
                 hir::Constness::NotConst
@@ -779,17 +776,13 @@ impl Item {
             | RequiredAssocTypeItem(..)
             | RequiredMethodItem(..)
             | MethodItem(..) => {
-                let assoc_item = tcx.associated_item(def_id);
-                let is_trait_item = match assoc_item.container {
-                    ty::AssocItemContainer::Trait => true,
-                    ty::AssocItemContainer::Impl => {
-                        // Trait impl items always inherit the impl's visibility --
-                        // we don't want to show `pub`.
-                        tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
+                match tcx.associated_item(def_id).container {
+                    // Trait impl items always inherit the impl's visibility --
+                    // we don't want to show `pub`.
+                    ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
+                        return None;
                     }
-                };
-                if is_trait_item {
-                    return None;
+                    ty::AssocContainer::InherentImpl => {}
                 }
             }
             _ => {}
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 719b7c6ab89..0da42f38251 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -210,7 +210,7 @@ impl UrlFragment {
             &UrlFragment::Item(def_id) => {
                 let kind = match tcx.def_kind(def_id) {
                     DefKind::AssocFn => {
-                        if tcx.defaultness(def_id).has_value() {
+                        if tcx.associated_item(def_id).defaultness(tcx).has_value() {
                             "method."
                         } else {
                             "tymethod."
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 23e7c7251cf..49cd2671dc0 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{
-    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
+    AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyCtxt;
@@ -177,7 +177,9 @@ impl LateLintPass<'_> for DisallowedMacros {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
         self.check(cx, item.span, None);
-        self.check(cx, item.vis_span, None);
+        if let ImplItemImplKind::Inherent { vis_span, .. } = item.impl_kind {
+            self.check(cx, vis_span, None);
+        }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index f8e8f5544b9..e25611d4881 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::{Applicability, MultiSpan};
-use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_hir::hir_id::OwnerId;
+use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef};
 use rustc_lint::LateContext;
 use rustc_span::Span;
@@ -19,7 +18,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
             of_trait: Some(of_trait),
             ..
         }) = &parent_item.kind
-        && let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id)
+        && let Some(did) = cx.tcx.trait_item_of(item.owner_id)
         && !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits)
     {
         let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id);
@@ -87,11 +86,6 @@ impl RenamedFnArgs {
     }
 }
 
-/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item.
-fn trait_item_def_id_of_impl(cx: &LateContext<'_>, target: OwnerId) -> Option<DefId> {
-    cx.tcx.associated_item(target).trait_item_def_id
-}
-
 fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool {
     of_trait
         .trait_def_id()
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index ba1ad599e11..bee3b19b597 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
-    FnRetTy, GenericBound, ImplItem, Item, Node, OpaqueTy, TraitRef, Ty, TyKind,
+    FnRetTy, GenericBound, Node, OpaqueTy, TraitRef, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
@@ -60,8 +60,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
             && let ExprKind::Block(block, _) = body.value.kind
             && block.stmts.is_empty()
             && let Some(closure_body) = desugared_async_block(cx, block)
-            && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
-                cx.tcx.hir_node_by_def_id(fn_def_id)
+            && let Some(vis_span_opt) = match cx.tcx.hir_node_by_def_id(fn_def_id) {
+                Node::Item(item) => Some(Some(item.vis_span)),
+                Node::ImplItem(impl_item) => Some(impl_item.vis_span()),
+                _ => None,
+            }
             && !span.from_expansion()
         {
             let header_span = span.with_hi(ret_ty.span.hi());
@@ -72,7 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
                 header_span,
                 "this function can be simplified using the `async fn` syntax",
                 |diag| {
-                    if let Some(vis_snip) = vis_span.get_source_text(cx)
+                    if let Some(vis_span) = vis_span_opt
+                        && let Some(vis_snip) = vis_span.get_source_text(cx)
                         && let Some(header_snip) = header_span.get_source_text(cx)
                         && let Some(ret_pos) = position_before_rarrow(&header_snip)
                         && let Some((_, ret_snip)) = suggested_ret(cx, output)
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index dbce29a8631..6258e408217 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -5,8 +5,8 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item};
 use rustc_hir::{
-    GenericParamKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem,
-    UsePath,
+    GenericParamKind, HirId, Impl, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind, ItemLocalId, Node, Pat,
+    PatKind, TraitItem, UsePath,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
@@ -256,7 +256,7 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>, ident: Ident) -> bo
 }
 
 fn get_param_name(impl_item: &ImplItem<'_>, cx: &LateContext<'_>, ident: Ident) -> Option<Symbol> {
-    if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
+    if let ImplItemImplKind::Trait { trait_item_def_id: Ok(trait_item_def_id), .. } = impl_item.impl_kind {
         let trait_param_names = cx.tcx.fn_arg_idents(trait_item_def_id);
 
         let ImplItemKind::Fn(_, body_id) = impl_item.kind else {
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index a6be7581c9a..a63ad978626 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -158,13 +158,23 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
         let mir = cx.tcx.optimized_mir(def_id);
 
         if let Ok(()) = is_min_const_fn(cx, mir, self.msrv)
-            && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) =
-                cx.tcx.hir_node_by_def_id(def_id)
+            && let node = cx.tcx.hir_node_by_def_id(def_id)
+            && let Some((item_span, vis_span_opt)) = match node {
+                hir::Node::Item(item) => Some((item.span, Some(item.vis_span))),
+                hir::Node::ImplItem(impl_item) => Some((impl_item.span, impl_item.vis_span())),
+                _ => None,
+            }
         {
-            let suggestion = if vis_span.is_empty() { "const " } else { " const" };
+            let (sugg_span, suggestion) = if let Some(vis_span) = vis_span_opt
+                && !vis_span.is_empty()
+            {
+                (vis_span.shrink_to_hi(), " const")
+            } else {
+                (item_span.shrink_to_lo(), "const ")
+            };
             span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| {
                 diag.span_suggestion_verbose(
-                    vis_span.shrink_to_hi(),
+                    sugg_span,
                     "make the function `const`",
                     suggestion,
                     Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 7772051eb5c..39b5964bd87 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -16,7 +16,7 @@ use rustc_hir::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::Visibility;
+use rustc_middle::ty::{AssocContainer, Visibility};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::symbol::kw;
@@ -246,12 +246,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
-            if cx.tcx.impl_trait_ref(cid).is_some() {
+        match cx.tcx.associated_item(impl_item.owner_id).container {
+            AssocContainer::Trait | AssocContainer::TraitImpl(_) => {
                 note_prev_span_then_ret!(self.prev_span, impl_item.span);
-            }
-        } else {
-            note_prev_span_then_ret!(self.prev_span, impl_item.span);
+            },
+            AssocContainer::InherentImpl => {}
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 28555a61090..6323e728666 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -3,7 +3,7 @@ use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, Attribute, find_attr};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::AssocItemContainer;
+use rustc_middle::ty::AssocContainer;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -166,8 +166,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
         let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
         let container_id = assoc_item.container_id(cx.tcx);
         let trait_def_id = match assoc_item.container {
-            AssocItemContainer::Trait => Some(container_id),
-            AssocItemContainer::Impl => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
+            AssocContainer::Trait => Some(container_id),
+            AssocContainer::TraitImpl(_) => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
+            AssocContainer::InherentImpl => None,
         };
 
         if let Some(trait_def_id) = trait_def_id
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 9cc93bf0653..8e9400e9d58 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
                 .tcx
                 .associated_items(item.owner_id)
                 .in_definition_order()
-                .filter_map(|assoc_item| assoc_item.trait_item_def_id)
+                .filter_map(|assoc_item| assoc_item.expect_trait_impl().ok())
                 .collect();
 
             for assoc in cx
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 809a6728e12..c4cad592e36 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                         .tcx
                         .impl_trait_ref(item.owner_id)
                         .map(EarlyBinder::instantiate_identity)
-                    && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
+                    && let Some(trait_item_id) = cx.tcx.trait_item_of(owner_id)
                 {
                     (
                         trait_item_id,
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index aeda864b7eb..8252e6d4869 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -151,8 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             // trait, not in the impl of the trait.
             let trait_method = cx
                 .tcx
-                .associated_item(impl_item.owner_id)
-                .trait_item_def_id
+                .trait_item_of(impl_item.owner_id)
                 .expect("impl method matches a trait method");
             let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity();
             let trait_method_sig = cx.tcx.instantiate_bound_regions_with_erased(trait_method_sig);
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index c4a759e919b..1a25c90d735 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -19,7 +19,7 @@ use rustc_ast::token::CommentKind;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
+    ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
     TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
 };
 use rustc_lint::{EarlyContext, LateContext, LintContext};
@@ -280,16 +280,17 @@ fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
 }
 
 fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
-    let (start_pat, end_pat) = match &item.kind {
+    let (mut start_pat, end_pat) = match &item.kind {
         ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
         ImplItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
         ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
     };
-    if item.vis_span.is_empty() {
-        (start_pat, end_pat)
-    } else {
-        (Pat::Str("pub"), end_pat)
-    }
+    if let ImplItemImplKind::Inherent { vis_span, .. } = item.impl_kind
+        && !vis_span.is_empty()
+    {
+        start_pat = Pat::Str("pub");
+    };
+    (start_pat, end_pat)
 }
 
 fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
@@ -313,21 +314,20 @@ fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
 }
 
 fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) {
-    let (start_pat, end_pat) = match kind {
+    let (mut start_pat, end_pat) = match kind {
         FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
         FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
         FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, body.value).1),
     };
-    let start_pat = match tcx.hir_node(hir_id) {
-        Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
-            if vis_span.is_empty() {
-                start_pat
-            } else {
-                Pat::Str("pub")
+    match tcx.hir_node(hir_id) {
+        Node::Item(Item { vis_span, .. })
+        | Node::ImplItem(ImplItem { impl_kind: ImplItemImplKind::Inherent { vis_span, .. }, .. }) => {
+            if !vis_span.is_empty() {
+                start_pat = Pat::Str("pub")
             }
         },
-        Node::TraitItem(_) => start_pat,
-        _ => Pat::Str(""),
+        Node::ImplItem(_) | Node::TraitItem(_) => {},
+        _ => start_pat = Pat::Str(""),
     };
     (start_pat, end_pat)
 }
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index e1077bdf4b1..120ab2e717d 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -3244,8 +3244,8 @@ pub fn get_path_from_caller_to_method_type<'tcx>(
     let assoc_item = tcx.associated_item(method);
     let def_id = assoc_item.container_id(tcx);
     match assoc_item.container {
-        rustc_ty::AssocItemContainer::Trait => get_path_to_callee(tcx, from, def_id),
-        rustc_ty::AssocItemContainer::Impl => {
+        rustc_ty::AssocContainer::Trait => get_path_to_callee(tcx, from, def_id),
+        rustc_ty::AssocContainer::InherentImpl | rustc_ty::AssocContainer::TraitImpl(_) => {
             let ty = tcx.type_of(def_id).instantiate_identity();
             get_path_to_ty(tcx, from, ty, args)
         },
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 857953072c4..1277fd225eb 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -1446,6 +1446,7 @@ pub(crate) fn make_test_description<R: Read>(
     cache: &DirectivesCache,
     name: String,
     path: &Utf8Path,
+    filterable_path: &Utf8Path,
     src: R,
     test_revision: Option<&str>,
     poisoned: &mut bool,
@@ -1520,7 +1521,13 @@ pub(crate) fn make_test_description<R: Read>(
         _ => ShouldPanic::No,
     };
 
-    CollectedTestDesc { name, ignore, ignore_message, should_panic }
+    CollectedTestDesc {
+        name,
+        filterable_path: filterable_path.to_owned(),
+        ignore,
+        ignore_message,
+        should_panic,
+    }
 }
 
 fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 33a02eb29fd..16cf76be9a5 100644
--- a/src/tools/compiletest/src/directives/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -14,6 +14,7 @@ fn make_test_description<R: Read>(
     config: &Config,
     name: String,
     path: &Utf8Path,
+    filterable_path: &Utf8Path,
     src: R,
     revision: Option<&str>,
 ) -> CollectedTestDesc {
@@ -24,6 +25,7 @@ fn make_test_description<R: Read>(
         &cache,
         name,
         path,
+        filterable_path,
         src,
         revision,
         &mut poisoned,
@@ -221,7 +223,7 @@ fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
 fn check_ignore(config: &Config, contents: &str) -> bool {
     let tn = String::new();
     let p = Utf8Path::new("a.rs");
-    let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None);
+    let d = make_test_description(&config, tn, p, p, std::io::Cursor::new(contents), None);
     d.ignore
 }
 
@@ -231,9 +233,9 @@ fn should_fail() {
     let tn = String::new();
     let p = Utf8Path::new("a.rs");
 
-    let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None);
+    let d = make_test_description(&config, tn.clone(), p, p, std::io::Cursor::new(""), None);
     assert_eq!(d.should_panic, ShouldPanic::No);
-    let d = make_test_description(&config, tn, p, std::io::Cursor::new("//@ should-fail"), None);
+    let d = make_test_description(&config, tn, p, p, std::io::Cursor::new("//@ should-fail"), None);
     assert_eq!(d.should_panic, ShouldPanic::Yes);
 }
 
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index b0dc24798b6..37cc17351d5 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -12,6 +12,8 @@ use std::num::NonZero;
 use std::sync::{Arc, Mutex, mpsc};
 use std::{env, hint, io, mem, panic, thread};
 
+use camino::Utf8PathBuf;
+
 use crate::common::{Config, TestPaths};
 use crate::output_capture::{self, ConsoleOut};
 use crate::panic_hook;
@@ -293,8 +295,12 @@ fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest>
     let mut filtered = tests;
 
     let matches_filter = |test: &CollectedTest, filter_str: &str| {
-        let test_name = &test.desc.name;
-        if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) }
+        let filterable_path = test.desc.filterable_path.as_str();
+        if opts.filter_exact {
+            filterable_path == filter_str
+        } else {
+            filterable_path.contains(filter_str)
+        }
     };
 
     // Remove tests that don't match the test filter
@@ -339,6 +345,7 @@ pub(crate) struct CollectedTest {
 /// Information that was historically needed to create a libtest `TestDesc`.
 pub(crate) struct CollectedTestDesc {
     pub(crate) name: String,
+    pub(crate) filterable_path: Utf8PathBuf,
     pub(crate) ignore: bool,
     pub(crate) ignore_message: Option<Cow<'static, str>>,
     pub(crate) should_panic: ShouldPanic,
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index f647f96a9bf..5e349a20ed2 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -317,11 +317,17 @@ pub fn parse_config(args: Vec<String>) -> Config {
             .free
             .iter()
             .map(|f| {
+                // Here `f` is relative to `./tests/run-make`. So if you run
+                //
+                //   ./x test tests/run-make/crate-loading
+                //
+                //  then `f` is "crate-loading".
                 let path = Utf8Path::new(f);
                 let mut iter = path.iter().skip(1);
 
-                // We skip the test folder and check if the user passed `rmake.rs`.
                 if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
+                    // Strip the "rmake.rs" suffix. For example, if `f` is
+                    // "crate-loading/rmake.rs" then this gives us "crate-loading".
                     path.parent().unwrap().to_string()
                 } else {
                     f.to_string()
@@ -329,6 +335,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
             })
             .collect::<Vec<_>>()
     } else {
+        // Note that the filters are relative to the root dir of the different test
+        // suites. For example, with:
+        //
+        //   ./x test tests/ui/lint/unused
+        //
+        // the filter is "lint/unused".
         matches.free.clone()
     };
     let compare_mode = matches.opt_str("compare-mode").map(|s| {
@@ -911,7 +923,8 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
     collector.tests.extend(revisions.into_iter().map(|revision| {
         // Create a test name and description to hand over to the executor.
         let src_file = fs::File::open(&test_path).expect("open test file to parse ignores");
-        let test_name = make_test_name(&cx.config, testpaths, revision);
+        let (test_name, filterable_path) =
+            make_test_name_and_filterable_path(&cx.config, testpaths, revision);
         // Create a description struct for the test/revision.
         // This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
         // because they historically needed to set the libtest ignored flag.
@@ -920,6 +933,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
             &cx.cache,
             test_name,
             &test_path,
+            &filterable_path,
             src_file,
             revision,
             &mut collector.poisoned,
@@ -1072,7 +1086,11 @@ impl Stamp {
 }
 
 /// Creates a name for this test/revision that can be handed over to the executor.
-fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String {
+fn make_test_name_and_filterable_path(
+    config: &Config,
+    testpaths: &TestPaths,
+    revision: Option<&str>,
+) -> (String, Utf8PathBuf) {
     // Print the name of the file, relative to the sources root.
     let path = testpaths.file.strip_prefix(&config.src_root).unwrap();
     let debugger = match config.debugger {
@@ -1084,14 +1102,23 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>
         None => String::new(),
     };
 
-    format!(
+    let name = format!(
         "[{}{}{}] {}{}",
         config.mode,
         debugger,
         mode_suffix,
         path,
         revision.map_or("".to_string(), |rev| format!("#{}", rev))
-    )
+    );
+
+    // `path` is the full path from the repo root like, `tests/ui/foo/bar.rs`.
+    // Filtering is applied without the `tests/ui/` part, so strip that off.
+    // First strip off "tests" to make sure we don't have some unexpected path.
+    let mut filterable_path = path.strip_prefix("tests").unwrap().to_owned();
+    // Now strip off e.g. "ui" or "run-make" component.
+    filterable_path = filterable_path.components().skip(1).collect();
+
+    (name, filterable_path)
 }
 
 /// Checks that test discovery didn't find any tests whose name stem is a prefix
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index a9804761400..568ec0c1198 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -48,40 +48,116 @@ const LICENSES: &[&str] = &[
 
 type ExceptionList = &'static [(&'static str, &'static str)];
 
+#[derive(Clone, Copy)]
+pub(crate) struct WorkspaceInfo<'a> {
+    /// Path to the directory containing the workspace root Cargo.toml file.
+    pub(crate) path: &'a str,
+    /// The list of license exceptions.
+    pub(crate) exceptions: ExceptionList,
+    /// Optionally:
+    /// * A list of crates for which dependencies need to be explicitly allowed.
+    /// * The list of allowed dependencies.
+    /// * The source code location of the allowed dependencies list
+    crates_and_deps: Option<(&'a [&'a str], &'a [&'a str], ListLocation)>,
+    /// Submodules required for the workspace
+    pub(crate) submodules: &'a [&'a str],
+}
+
 /// The workspaces to check for licensing and optionally permitted dependencies.
-///
-/// Each entry consists of a tuple with the following elements:
-///
-/// * The path to the workspace root Cargo.toml file.
-/// * The list of license exceptions.
-/// * Optionally a tuple of:
-///     * A list of crates for which dependencies need to be explicitly allowed.
-///     * The list of allowed dependencies.
-/// * Submodules required for the workspace.
 // FIXME auto detect all cargo workspaces
-pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[
+pub(crate) const WORKSPACES: &[WorkspaceInfo<'static>] = &[
     // The root workspace has to be first for check_rustfix to work.
-    (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]),
-    ("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]),
-    // Outside of the alphabetical section because rustfmt formats it using multiple lines.
-    (
-        "compiler/rustc_codegen_cranelift",
-        EXCEPTIONS_CRANELIFT,
-        Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
-        &[],
-    ),
-    // tidy-alphabetical-start
-    ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]),
-    ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]),
-    ("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]),
-    //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
-    //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
-    ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]),
-    ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
-    ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
-    ("src/tools/test-float-parse", EXCEPTIONS, None, &[]),
-    ("tests/run-make-cargo/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
-    // tidy-alphabetical-end
+    WorkspaceInfo {
+        path: ".",
+        exceptions: EXCEPTIONS,
+        crates_and_deps: Some((
+            &["rustc-main"],
+            PERMITTED_RUSTC_DEPENDENCIES,
+            PERMITTED_RUSTC_DEPS_LOCATION,
+        )),
+        submodules: &[],
+    },
+    WorkspaceInfo {
+        path: "library",
+        exceptions: EXCEPTIONS_STDLIB,
+        crates_and_deps: Some((
+            &["sysroot"],
+            PERMITTED_STDLIB_DEPENDENCIES,
+            PERMITTED_STDLIB_DEPS_LOCATION,
+        )),
+        submodules: &[],
+    },
+    {
+        WorkspaceInfo {
+            path: "compiler/rustc_codegen_cranelift",
+            exceptions: EXCEPTIONS_CRANELIFT,
+            crates_and_deps: Some((
+                &["rustc_codegen_cranelift"],
+                PERMITTED_CRANELIFT_DEPENDENCIES,
+                PERMITTED_CRANELIFT_DEPS_LOCATION,
+            )),
+            submodules: &[],
+        }
+    },
+    WorkspaceInfo {
+        path: "compiler/rustc_codegen_gcc",
+        exceptions: EXCEPTIONS_GCC,
+        crates_and_deps: None,
+        submodules: &[],
+    },
+    WorkspaceInfo {
+        path: "src/bootstrap",
+        exceptions: EXCEPTIONS_BOOTSTRAP,
+        crates_and_deps: None,
+        submodules: &[],
+    },
+    WorkspaceInfo {
+        path: "src/tools/cargo",
+        exceptions: EXCEPTIONS_CARGO,
+        crates_and_deps: None,
+        submodules: &["src/tools/cargo"],
+    },
+    // FIXME uncomment once all deps are vendored
+    //  WorkspaceInfo {
+    //      path: "src/tools/miri/test-cargo-miri",
+    //      crates_and_deps: None
+    //      submodules: &[],
+    //  },
+    // WorkspaceInfo {
+    //      path: "src/tools/miri/test_dependencies",
+    //      crates_and_deps: None,
+    //      submodules: &[],
+    //  }
+    WorkspaceInfo {
+        path: "src/tools/rust-analyzer",
+        exceptions: EXCEPTIONS_RUST_ANALYZER,
+        crates_and_deps: None,
+        submodules: &[],
+    },
+    WorkspaceInfo {
+        path: "src/tools/rustbook",
+        exceptions: EXCEPTIONS_RUSTBOOK,
+        crates_and_deps: None,
+        submodules: &["src/doc/book", "src/doc/reference"],
+    },
+    WorkspaceInfo {
+        path: "src/tools/rustc-perf",
+        exceptions: EXCEPTIONS_RUSTC_PERF,
+        crates_and_deps: None,
+        submodules: &["src/tools/rustc-perf"],
+    },
+    WorkspaceInfo {
+        path: "src/tools/test-float-parse",
+        exceptions: EXCEPTIONS,
+        crates_and_deps: None,
+        submodules: &[],
+    },
+    WorkspaceInfo {
+        path: "tests/run-make-cargo/uefi-qemu/uefi_qemu_test",
+        exceptions: EXCEPTIONS_UEFI_QEMU_TEST,
+        crates_and_deps: None,
+        submodules: &[],
+    },
 ];
 
 /// These are exceptions to Rust's permissive licensing policy, and
@@ -226,7 +302,20 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[
     ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptable, but we use it under MIT OR Apache-2.0
 ];
 
-const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
+#[derive(Clone, Copy)]
+struct ListLocation {
+    path: &'static str,
+    line: u32,
+}
+
+/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start);
+macro_rules! location {
+    (+ $offset:literal) => {
+        ListLocation { path: file!(), line: line!() + $offset }
+    };
+}
+
+const PERMITTED_RUSTC_DEPS_LOCATION: ListLocation = location!(+6);
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
 ///
@@ -458,6 +547,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-end
 ];
 
+const PERMITTED_STDLIB_DEPS_LOCATION: ListLocation = location!(+2);
+
 const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "addr2line",
@@ -499,6 +590,8 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-end
 ];
 
+const PERMITTED_CRANELIFT_DEPS_LOCATION: ListLocation = location!(+2);
+
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "allocator-api2",
@@ -573,29 +666,30 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
 
     check_proc_macro_dep_list(root, cargo, bless, bad);
 
-    for &(workspace, exceptions, permitted_deps, submodules) in WORKSPACES {
+    for &WorkspaceInfo { path, exceptions, crates_and_deps, submodules } in WORKSPACES {
         if has_missing_submodule(root, submodules) {
             continue;
         }
 
-        if !root.join(workspace).join("Cargo.lock").exists() {
-            tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
+        if !root.join(path).join("Cargo.lock").exists() {
+            tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
             continue;
         }
 
         let mut cmd = cargo_metadata::MetadataCommand::new();
         cmd.cargo_path(cargo)
-            .manifest_path(root.join(workspace).join("Cargo.toml"))
+            .manifest_path(root.join(path).join("Cargo.toml"))
             .features(cargo_metadata::CargoOpt::AllFeatures)
             .other_options(vec!["--locked".to_owned()]);
         let metadata = t!(cmd.exec());
 
-        check_license_exceptions(&metadata, workspace, exceptions, bad);
-        if let Some((crates, permitted_deps)) = permitted_deps {
-            check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
+        check_license_exceptions(&metadata, path, exceptions, bad);
+        if let Some((crates, permitted_deps, location)) = crates_and_deps {
+            let descr = crates.get(0).unwrap_or(&path);
+            check_permitted_dependencies(&metadata, descr, permitted_deps, crates, location, bad);
         }
 
-        if workspace == "library" {
+        if path == "library" {
             check_runtime_license_exceptions(&metadata, bad);
             check_runtime_no_duplicate_dependencies(&metadata, bad);
             check_runtime_no_proc_macros(&metadata, bad);
@@ -840,6 +934,7 @@ fn check_permitted_dependencies(
     descr: &str,
     permitted_dependencies: &[&'static str],
     restricted_dependency_crates: &[&'static str],
+    permitted_location: ListLocation,
     bad: &mut bool,
 ) {
     let mut has_permitted_dep_error = false;
@@ -900,7 +995,7 @@ fn check_permitted_dependencies(
     }
 
     if has_permitted_dep_error {
-        eprintln!("Go to `{PERMITTED_DEPS_LOCATION}` for the list.");
+        eprintln!("Go to `{}:{}` for the list.", permitted_location.path, permitted_location.line);
     }
 }
 
diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs
index bc217a55cc1..2b212cfa67a 100644
--- a/src/tools/tidy/src/extdeps.rs
+++ b/src/tools/tidy/src/extdeps.rs
@@ -3,6 +3,8 @@
 use std::fs;
 use std::path::Path;
 
+use crate::deps::WorkspaceInfo;
+
 /// List of allowed sources for packages.
 const ALLOWED_SOURCES: &[&str] = &[
     r#""registry+https://github.com/rust-lang/crates.io-index""#,
@@ -13,22 +15,22 @@ const ALLOWED_SOURCES: &[&str] = &[
 /// Checks for external package sources. `root` is the path to the directory that contains the
 /// workspace `Cargo.toml`.
 pub fn check(root: &Path, bad: &mut bool) {
-    for &(workspace, _, _, submodules) in crate::deps::WORKSPACES {
+    for &WorkspaceInfo { path, submodules, .. } in crate::deps::WORKSPACES {
         if crate::deps::has_missing_submodule(root, submodules) {
             continue;
         }
 
         // FIXME check other workspaces too
         // `Cargo.lock` of rust.
-        let path = root.join(workspace).join("Cargo.lock");
+        let lockfile = root.join(path).join("Cargo.lock");
 
-        if !path.exists() {
-            tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
+        if !lockfile.exists() {
+            tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
             continue;
         }
 
         // Open and read the whole file.
-        let cargo_lock = t!(fs::read_to_string(&path));
+        let cargo_lock = t!(fs::read_to_string(&lockfile));
 
         // Process each line.
         for line in cargo_lock.lines() {
diff --git a/src/tools/tidy/src/fluent_lowercase.rs b/src/tools/tidy/src/fluent_lowercase.rs
new file mode 100644
index 00000000000..13f0319909e
--- /dev/null
+++ b/src/tools/tidy/src/fluent_lowercase.rs
@@ -0,0 +1,64 @@
+//! Checks that the error messages start with a lowercased letter (except when allowed to).
+
+use std::path::Path;
+
+use fluent_syntax::ast::{Entry, Message, PatternElement};
+
+use crate::walk::{filter_dirs, walk};
+
+#[rustfmt::skip]
+const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[
+    // tidy-alphabetical-start
+    "ABI",
+    "ABIs",
+    "ADT",
+    "C",
+    "CGU",
+    "Ferris",
+    "MIR",
+    "OK",
+    "Rust",
+    "VS", // VS Code
+    // tidy-alphabetical-end
+];
+
+fn filter_fluent(path: &Path) -> bool {
+    if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
+}
+
+fn is_allowed_capitalized_word(msg: &str) -> bool {
+    ALLOWED_CAPITALIZED_WORDS.iter().any(|word| {
+        msg.strip_prefix(word)
+            .map(|tail| tail.chars().next().map(|c| c == '-' || c.is_whitespace()).unwrap_or(true))
+            .unwrap_or_default()
+    })
+}
+
+fn check_lowercase(filename: &str, contents: &str, bad: &mut bool) {
+    let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
+
+    for entry in &parse.body {
+        if let Entry::Message(msg) = entry
+            && let Message { value: Some(pattern), .. } = msg
+            && let [first_pattern, ..] = &pattern.elements[..]
+            && let PatternElement::TextElement { value } = first_pattern
+            && value.chars().next().is_some_and(char::is_uppercase)
+            && !is_allowed_capitalized_word(value)
+        {
+            tidy_error!(
+                bad,
+                "{filename}: message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`"
+            );
+        }
+    }
+}
+
+pub fn check(path: &Path, bad: &mut bool) {
+    walk(
+        path,
+        |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
+        &mut |ent, contents| {
+            check_lowercase(ent.path().to_str().unwrap(), contents, bad);
+        },
+    );
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 37713cbf75e..2a9c3963d2d 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -257,6 +257,7 @@ pub mod extra_checks;
 pub mod features;
 pub mod filenames;
 pub mod fluent_alphabetical;
+pub mod fluent_lowercase;
 pub mod fluent_period;
 mod fluent_used;
 pub mod gcc_submodule;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index bfe30258915..f9e82341b7a 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -121,6 +121,7 @@ fn main() {
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info);
         check!(fluent_alphabetical, &compiler_path, bless);
         check!(fluent_period, &compiler_path);
+        check!(fluent_lowercase, &compiler_path);
         check!(target_policy, &root_path);
         check!(gcc_submodule, &root_path, &compiler_path);
 
diff --git a/src/version b/src/version
index 6979a6c0661..7f229af9647 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.91.0
+1.92.0
diff --git a/tests/codegen-llvm/c-variadic-lifetime.rs b/tests/codegen-llvm/c-variadic-lifetime.rs
index 5b2f8af18c8..c6d3602ef51 100644
--- a/tests/codegen-llvm/c-variadic-lifetime.rs
+++ b/tests/codegen-llvm/c-variadic-lifetime.rs
@@ -8,7 +8,7 @@
 
 #[unsafe(no_mangle)]
 unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
-    // CHECK: call void @llvm.lifetime.start.p0(i64 {{[0-9]+}}, ptr nonnull %args)
+    // CHECK: call void @llvm.lifetime.start.p0({{(i64 [0-9]+, )?}}ptr nonnull %args)
     // CHECK: call void @llvm.va_start.p0(ptr nonnull %args)
 
     let b = args.arg::<f64>();
@@ -17,5 +17,5 @@ unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
     a + b + c
 
     // CHECK: call void @llvm.va_end.p0(ptr nonnull %args)
-    // CHECK: call void @llvm.lifetime.end.p0(i64 {{[0-9]+}}, ptr nonnull %args)
+    // CHECK: call void @llvm.lifetime.end.p0({{(i64 [0-9]+, )?}}ptr nonnull %args)
 }
diff --git a/tests/codegen-llvm/cffi/c-variadic-inline.rs b/tests/codegen-llvm/cffi/c-variadic-inline.rs
new file mode 100644
index 00000000000..369b7e571ca
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-inline.rs
@@ -0,0 +1,47 @@
+//@ compile-flags: -C opt-level=3
+#![feature(c_variadic)]
+
+// Test that the inline attributes are accepted on C-variadic functions.
+//
+// Currently LLVM is unable to inline C-variadic functions, but that is valid because despite
+// the name even `#[inline(always)]` is just a hint.
+
+#[inline(always)]
+unsafe extern "C" fn inline_always(mut ap: ...) -> u32 {
+    ap.arg::<u32>()
+}
+
+#[inline]
+unsafe extern "C" fn inline(mut ap: ...) -> u32 {
+    ap.arg::<u32>()
+}
+
+#[inline(never)]
+unsafe extern "C" fn inline_never(mut ap: ...) -> u32 {
+    ap.arg::<u32>()
+}
+
+#[cold]
+unsafe extern "C" fn cold(mut ap: ...) -> u32 {
+    ap.arg::<u32>()
+}
+
+#[unsafe(no_mangle)]
+#[inline(never)]
+fn helper() {
+    // CHECK-LABEL: helper
+    // CHECK-LABEL: call c_variadic_inline::inline_always
+    // CHECK-LABEL: call c_variadic_inline::inline
+    // CHECK-LABEL: call c_variadic_inline::inline_never
+    // CHECK-LABEL: call c_variadic_inline::cold
+    unsafe {
+        inline_always(1);
+        inline(2);
+        inline_never(3);
+        cold(4);
+    }
+}
+
+fn main() {
+    helper()
+}
diff --git a/tests/ui/c-variadic/naked.rs b/tests/ui/c-variadic/naked.rs
new file mode 100644
index 00000000000..46b59395485
--- /dev/null
+++ b/tests/ui/c-variadic/naked.rs
@@ -0,0 +1,40 @@
+//@ run-pass
+//@ only-x86_64
+//@ only-linux
+#![feature(c_variadic)]
+
+#[repr(C)]
+#[derive(Debug, PartialEq)]
+struct Data(i32, f64);
+
+#[unsafe(naked)]
+unsafe extern "C" fn c_variadic(_: ...) -> Data {
+    // This assembly was generated with GCC, because clang/LLVM is unable to
+    // optimize out the spilling of all registers to the stack.
+    core::arch::naked_asm!(
+        "        sub     rsp, 96",
+        "        mov     QWORD PTR [rsp-88], rdi",
+        "        test    al, al",
+        "        je      .L7",
+        "        movaps  XMMWORD PTR [rsp-40], xmm0",
+        ".L7:",
+        "        lea     rax, [rsp+104]",
+        "        mov     rcx, QWORD PTR [rsp-40]",
+        "        mov     DWORD PTR [rsp-112], 0",
+        "        mov     QWORD PTR [rsp-104], rax",
+        "        lea     rax, [rsp-88]",
+        "        mov     QWORD PTR [rsp-96], rax",
+        "        movq    xmm0, rcx",
+        "        mov     eax, DWORD PTR [rsp-88]",
+        "        mov     DWORD PTR [rsp-108], 48",
+        "        add     rsp, 96",
+        "        ret",
+    )
+}
+
+fn main() {
+    unsafe {
+        assert_eq!(c_variadic(1, 2.0), Data(1, 2.0));
+        assert_eq!(c_variadic(123, 4.56), Data(123, 4.56));
+    }
+}
diff --git a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs b/tests/ui/const-generics/generic_arg_infer/paren_infer.rs
index 9d7df8016cb..869683b7056 100644
--- a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs
+++ b/tests/ui/const-generics/generic_arg_infer/paren_infer.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+//@ reference: items.generics.const.inferred
 
 struct Foo<const N: usize>;
 
diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs
index 478fa3706e8..9af351ec59f 100644
--- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs
+++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs
@@ -11,7 +11,6 @@ where
 {
     fn unimplemented(self, _: &Foo) -> Self::Output {
         //~^ ERROR method `unimplemented` is not a member of trait `std::ops::Add`
-        //~| ERROR type annotations needed
         loop {}
     }
 }
diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr
index 29bbd23a469..37eb895f9a8 100644
--- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr
@@ -3,7 +3,6 @@ error[E0407]: method `unimplemented` is not a member of trait `std::ops::Add`
    |
 LL | /     fn unimplemented(self, _: &Foo) -> Self::Output {
 LL | |
-LL | |
 LL | |         loop {}
 LL | |     }
    | |_____^ not a member of trait `std::ops::Add`
@@ -39,21 +38,7 @@ LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo
    = note: expressions using a const parameter must map each value to a distinct output value
    = note: proving the result of expressions other than the parameter are unique is not supported
 
-error[E0284]: type annotations needed
-  --> $DIR/post-analysis-user-facing-param-env.rs:12:40
-   |
-LL |     fn unimplemented(self, _: &Foo) -> Self::Output {
-   |                                        ^^^^^^^^^^^^ cannot infer the value of const parameter `NUM`
-   |
-note: required for `Foo` to implement `Add<&'a Foo>`
-  --> $DIR/post-analysis-user-facing-param-env.rs:6:28
-   |
-LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo
-   |          ----------------  ^^^^^^^^^^^^^^^^^^^^^^     ^^^
-   |          |
-   |          unsatisfied trait bound introduced here
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0046, E0207, E0284, E0407.
+Some errors have detailed explanations: E0046, E0207, E0407.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs
index 198f8d1bc10..6d12ab1e4cf 100644
--- a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs
+++ b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs
@@ -2,6 +2,7 @@
 // dist artifacts.
 
 //@ only-dist
+//@ only-nightly (cranelift is not stable yet)
 //@ only-x86_64-unknown-linux-gnu
 //@ compile-flags: -Z codegen-backend=cranelift
 //@ run-pass
diff --git a/tests/ui/explicit-tail-calls/c-variadic.rs b/tests/ui/explicit-tail-calls/c-variadic.rs
new file mode 100644
index 00000000000..e6eebe4228e
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/c-variadic.rs
@@ -0,0 +1,14 @@
+#![expect(incomplete_features)]
+#![feature(c_variadic, explicit_tail_calls)]
+#![allow(unused)]
+
+unsafe extern "C" fn foo(mut ap: ...) -> u32 {
+    ap.arg::<u32>()
+}
+
+extern "C" fn bar() -> u32 {
+    unsafe { become foo(1, 2, 3) }
+    //~^ ERROR c-variadic functions can't be tail-called
+}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/c-variadic.stderr b/tests/ui/explicit-tail-calls/c-variadic.stderr
new file mode 100644
index 00000000000..5293339d218
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/c-variadic.stderr
@@ -0,0 +1,8 @@
+error: c-variadic functions can't be tail-called
+  --> $DIR/c-variadic.rs:10:14
+   |
+LL |     unsafe { become foo(1, 2, 3) }
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs
index 92cb60bb16d..dac878c1cd9 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs
@@ -20,4 +20,4 @@ pub fn lib_main() {
     unsafe { f(42); }
 }
 
-//~? ERROR Dlltool could not create import library with
+//~? ERROR dlltool could not create import library with
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr
index 90cca83d1c1..5f3c29c3a21 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr
@@ -1,4 +1,4 @@
-error: Dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX:
+error: dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX:
        
        $DLLTOOL: Syntax error in def file $DEF_FILE:1␍
 
diff --git a/tests/ui/macros/issue-61053-duplicate-binder.stderr b/tests/ui/macros/issue-61053-duplicate-binder.stderr
index 7c7cb26b407..1ecbc3f86d0 100644
--- a/tests/ui/macros/issue-61053-duplicate-binder.stderr
+++ b/tests/ui/macros/issue-61053-duplicate-binder.stderr
@@ -2,9 +2,9 @@ error: duplicate matcher binding
   --> $DIR/issue-61053-duplicate-binder.rs:7:20
    |
 LL |             ($x:tt $x:tt) => { $x };
-   |              --    ^^
+   |              --    ^^ duplicate binding
    |              |
-   |              previous declaration
+   |              previous binding
    |
 note: the lint level is defined here
   --> $DIR/issue-61053-duplicate-binder.rs:1:9