about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml17
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--Cargo.lock32
-rw-r--r--compiler/rustc_ast/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs37
-rw-r--r--compiler/rustc_ast/src/visit.rs84
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs50
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs14
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/util.rs30
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs3
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml1
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs73
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch2
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs28
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs25
-rw-r--r--compiler/rustc_const_eval/Cargo.toml2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs17
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs19
-rw-r--r--compiler/rustc_data_structures/src/flock.rs2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs2
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs14
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation/tests.rs41
-rw-r--r--compiler/rustc_expand/Cargo.toml1
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs71
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs147
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs242
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs560
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml1
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs87
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs134
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs60
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs70
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs159
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs10
-rw-r--r--compiler/rustc_interface/src/passes.rs17
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/messages.ftl1
-rw-r--r--compiler/rustc_lint/src/early/diagnostics/check_cfg.rs8
-rw-r--r--compiler/rustc_lint/src/lints.rs10
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs3
-rw-r--r--compiler/rustc_lint/src/types/literal.rs12
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs58
-rw-r--r--compiler/rustc_macros/src/query.rs1
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/messages.ftl4
-rw-r--r--compiler/rustc_metadata/src/creader.rs21
-rw-r--r--compiler/rustc_metadata/src/errors.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs13
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs8
-rw-r--r--compiler/rustc_middle/src/query/erase.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs15
-rw-r--r--compiler/rustc_middle/src/ty/context.rs23
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs36
-rw-r--r--compiler/rustc_mir_build/src/builder/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs9
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml2
-rw-r--r--compiler/rustc_mir_transform/src/check_inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs22
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs38
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drop.rs45
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs7
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs2
-rw-r--r--compiler/rustc_monomorphize/Cargo.toml2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs7
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs62
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs24
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs10
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs44
-rw-r--r--compiler/rustc_passes/Cargo.toml2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs8
-rw-r--r--compiler/rustc_passes/src/lib_features.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs10
-rw-r--r--compiler/rustc_passes/src/stability.rs24
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs40
-rw-r--r--compiler/rustc_privacy/Cargo.toml2
-rw-r--r--compiler/rustc_privacy/src/lib.rs5
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs2
-rw-r--r--compiler/rustc_query_system/src/lib.rs2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs99
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs57
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_session/src/filesearch.rs4
-rw-r--r--compiler/rustc_session/src/options.rs1
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs31
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs6
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs8
-rw-r--r--compiler/rustc_target/src/target_features.rs12
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs22
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs14
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs37
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs76
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs23
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs58
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/select.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs143
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs161
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs10
-rw-r--r--compiler/rustc_traits/src/coroutine_witnesses.rs37
-rw-r--r--compiler/rustc_traits/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs98
-rw-r--r--compiler/rustc_type_ir/src/interner.rs11
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs10
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs33
-rw-r--r--library/alloc/src/slice.rs11
-rw-r--r--library/alloc/src/str.rs5
-rw-r--r--library/core/src/convert/mod.rs2
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/ffi/primitives.rs6
-rw-r--r--library/core/src/ffi/va_list.rs70
-rw-r--r--library/core/src/fmt/mod.rs10
-rw-r--r--library/core/src/hint.rs2
-rw-r--r--library/core/src/intrinsics/mod.rs317
-rw-r--r--library/core/src/iter/traits/collect.rs33
-rw-r--r--library/core/src/iter/traits/iterator.rs4
-rw-r--r--library/core/src/lib.rs7
-rw-r--r--library/core/src/macros/mod.rs20
-rw-r--r--library/core/src/marker.rs50
-rw-r--r--library/core/src/mem/mod.rs2
-rw-r--r--library/core/src/num/f32.rs810
-rw-r--r--library/core/src/num/f64.rs794
-rw-r--r--library/core/src/ops/arith.rs4
-rw-r--r--library/core/src/ops/function.rs6
-rw-r--r--library/core/src/ops/index.rs6
-rw-r--r--library/core/src/ops/try_trait.rs18
-rw-r--r--library/core/src/option.rs30
-rw-r--r--library/core/src/pin.rs2
-rw-r--r--library/core/src/ptr/const_ptr.rs26
-rw-r--r--library/core/src/ptr/mod.rs293
-rw-r--r--library/core/src/ptr/mut_ptr.rs26
-rw-r--r--library/core/src/ptr/non_null.rs27
-rw-r--r--library/core/src/slice/index.rs2
-rw-r--r--library/core/src/slice/mod.rs14
-rw-r--r--library/core/src/slice/sort/select.rs4
-rw-r--r--library/core/src/slice/sort/stable/mod.rs6
-rw-r--r--library/core/src/slice/sort/unstable/mod.rs4
-rw-r--r--library/core/src/slice/sort/unstable/quicksort.rs4
-rw-r--r--library/core/src/sync/atomic.rs14
-rw-r--r--library/coretests/tests/floats/f32.rs142
-rw-r--r--library/coretests/tests/floats/f64.rs129
-rw-r--r--library/coretests/tests/lib.rs2
-rw-r--r--library/coretests/tests/macros.rs42
-rw-r--r--library/std/src/f32.rs26
-rw-r--r--library/std/src/f64.rs26
-rw-r--r--library/std/src/ffi/mod.rs2
-rw-r--r--library/std/src/ffi/os_str.rs2
-rw-r--r--library/std/src/fs.rs3
-rw-r--r--library/std/src/io/mod.rs53
-rw-r--r--library/std/src/io/pipe.rs38
-rw-r--r--library/std/src/io/tests.rs120
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/os/net/linux_ext/addr.rs6
-rw-r--r--library/std/src/os/net/linux_ext/socket.rs3
-rw-r--r--library/std/src/os/net/linux_ext/tcp.rs6
-rw-r--r--library/std/src/os/unix/process.rs18
-rw-r--r--library/std/src/path.rs2
-rw-r--r--library/std/src/process.rs14
-rw-r--r--library/std/src/sync/mpmc/list.rs2
-rw-r--r--library/std/src/sync/reentrant_lock.rs8
-rw-r--r--library/std/src/sys/net/connection/uefi/mod.rs59
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp.rs21
-rw-r--r--library/std/src/sys/net/connection/uefi/tcp4.rs118
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs10
-rw-r--r--library/std/src/sys/process/unix/common.rs127
-rw-r--r--library/std/src/sys/process/unix/common/cstring_array.rs115
-rw-r--r--library/std/src/sys/process/unix/unix.rs10
-rw-r--r--library/std/src/sys/process/unix/vxworks.rs6
-rw-r--r--library/std/src/sys/thread_local/guard/key.rs4
m---------library/stdarch0
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/perf.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs4
-rw-r--r--src/bootstrap/src/core/sanity.rs20
-rw-r--r--src/bootstrap/src/utils/cache.rs30
-rw-r--r--src/bootstrap/src/utils/cache/tests.rs20
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs34
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs113
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs11
-rw-r--r--src/ci/citool/src/jobs.rs14
-rw-r--r--src/ci/docker/host-x86_64/arm-android/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-android/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile35
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig (renamed from src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig)0
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile (renamed from src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile)10
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig13
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile41
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig14
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile (renamed from src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile)9
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig (renamed from src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig)0
-rwxr-xr-xsrc/ci/docker/run.sh5
-rwxr-xr-xsrc/ci/docker/scripts/build-powerpc64le-toolchain.sh (renamed from src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh)0
-rwxr-xr-xsrc/ci/docker/scripts/rfl-build.sh3
-rw-r--r--src/ci/github-actions/jobs.yml23
-rwxr-xr-xsrc/ci/scripts/install-clang.sh4
-rwxr-xr-xsrc/ci/scripts/install-mingw.sh2
-rwxr-xr-xsrc/ci/scripts/install-ninja.sh2
-rwxr-xr-xsrc/ci/scripts/install-sccache.sh2
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md2
-rw-r--r--src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md27
-rw-r--r--src/doc/rustc-dev-guide/src/cli.md2
-rw-r--r--src/doc/rustc-dev-guide/src/getting-started.md2
-rw-r--r--src/doc/rustc-dev-guide/src/rustc-driver/intro.md12
-rw-r--r--src/doc/rustc/src/platform-support/solaris.md1
-rw-r--r--src/doc/rustc/theme/pagetoc.css2
-rw-r--r--src/doc/rustdoc/src/write-documentation/the-doc-attribute.md6
-rw-r--r--src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md12
-rw-r--r--src/doc/unstable-book/src/compiler-flags/track-diagnostics.md11
-rw-r--r--src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md13
-rw-r--r--src/doc/unstable-book/src/language-features/explicit-extern-abis.md4
-rw-r--r--src/etc/rust_analyzer_eglot.el2
-rw-r--r--src/etc/rust_analyzer_helix.toml2
-rw-r--r--src/etc/rust_analyzer_settings.json2
-rw-r--r--src/etc/rust_analyzer_zed.json6
-rw-r--r--src/librustdoc/clean/types.rs30
-rw-r--r--src/librustdoc/clean/utils.rs53
-rw-r--r--src/librustdoc/clean/utils/tests.rs42
-rw-r--r--src/librustdoc/doctest.rs28
-rw-r--r--src/librustdoc/doctest/extracted.rs17
-rw-r--r--src/librustdoc/doctest/make.rs146
-rw-r--r--src/librustdoc/doctest/markdown.rs13
-rw-r--r--src/librustdoc/doctest/rust.rs23
-rw-r--r--src/librustdoc/doctest/tests.rs20
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/layout.rs19
-rw-r--r--src/librustdoc/html/markdown.rs6
-rw-r--r--src/librustdoc/html/render/context.rs7
-rw-r--r--src/librustdoc/html/render/mod.rs39
-rw-r--r--src/librustdoc/html/render/sidebar.rs10
-rw-r--r--src/librustdoc/html/render/write_shared.rs71
-rw-r--r--src/librustdoc/html/sources.rs21
-rw-r--r--src/librustdoc/html/static/js/main.js4
-rw-r--r--src/librustdoc/json/conversions.rs6
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs7
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs12
-rw-r--r--src/librustdoc/passes/propagate_stability.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs10
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/CONTRIBUTING.md6
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/development/basics.md2
-rw-r--r--src/tools/clippy/book/src/development/the_team.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md1
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs1
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/deprecate_lint.rs61
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs313
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs10
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/release.rs24
-rw-r--r--src/tools/clippy/clippy_dev/src/rename_lint.rs499
-rw-r--r--src/tools/clippy/clippy_dev/src/sync.rs13
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs160
-rw-r--r--src/tools/clippy/clippy_dev/src/utils.rs352
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs166
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_with_brackets.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ineffective_open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_count.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs415
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_split.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs1153
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/string_patterns.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_concat.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/dump_hir.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs8
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs6
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/produce_ice.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/symbols.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs8
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs40
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs70
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs86
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs254
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs11
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/src/driver.rs15
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr94
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed4
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr12
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed38
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs38
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.stderr30
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.rs77
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs (renamed from src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs)0
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs221
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr247
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs101
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr79
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs128
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr119
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs42
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr44
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs219
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr143
-rw-r--r--src/tools/clippy/tests/ui/cast.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_size.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs2
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.rs12
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.stderr42
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.fixed2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.stderr8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.stderr19
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6840.rs1
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9445.rs4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9445.stderr12
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.rs200
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr197
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs135
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr89
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs76
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr50
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs162
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr88
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs20
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr80
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/duplicated_attributes.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed8
-rw-r--r--src/tools/clippy/tests/ui/empty_structs_with_brackets.rs8
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.stderr6
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.fixed3
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.rs3
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr6
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.fixed11
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.rs11
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.stderr44
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed13
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.fixed13
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs12
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr62
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs2
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr22
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.rs2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed25
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.rs25
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr14
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.fixed142
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.rs20
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.stderr137
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.fixed53
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs49
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr255
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed24
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs19
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr86
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.rs40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.stderr (renamed from src/tools/clippy/tests/ui/assign_ops2.stderr)29
-rw-r--r--src/tools/clippy/tests/ui/needless_match.fixed12
-rw-r--r--src/tools/clippy/tests/ui/needless_match.rs15
-rw-r--r--src/tools/clippy/tests/ui/needless_match.stderr12
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed18
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs18
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr76
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs53
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed120
-rw-r--r--src/tools/clippy/tests/ui/rename.rs120
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr400
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.rs12
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr67
-rw-r--r--src/tools/clippy/tests/ui/single_range_in_vec_init.rs2
-rw-r--r--src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed)0
-rw-r--r--src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs)0
-rw-r--r--src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr)2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.stderr71
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed10
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs10
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.fixed41
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.rs41
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.stderr89
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed15
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs15
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr14
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs21
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr16
-rw-r--r--src/tools/clippy/triagebot.toml2
-rw-r--r--src/tools/miri/README.md3
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rwxr-xr-xsrc/tools/miri/ci/ci.sh13
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs2
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs3
-rw-r--r--src/tools/miri/src/alloc_bytes.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs20
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs2
-rw-r--r--src/tools/miri/src/concurrency/mod.rs2
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs5
-rw-r--r--src/tools/miri/src/helpers.rs23
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs2
-rw-r--r--src/tools/miri/src/lib.rs15
-rw-r--r--src/tools/miri/src/machine.rs7
-rw-r--r--src/tools/miri/src/shims/backtrace.rs8
-rw-r--r--src/tools/miri/src/shims/files.rs10
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs6
-rw-r--r--src/tools/miri/src/shims/io_error.rs24
-rw-r--r--src/tools/miri/src/shims/native_lib.rs25
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs4
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs66
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs6
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs2
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs6
-rw-r--r--src/tools/miri/src/shims/windows/env.rs6
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs110
-rw-r--r--src/tools/miri/src/shims/windows/fs.rs264
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs36
-rw-r--r--src/tools/miri/src/shims/x86/gfni.rs4
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs2
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs2
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs2
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml9
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs9
-rw-r--r--src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs1
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr4
-rw-r--r--src/tools/miri/tests/fail/shims/isolated_stdin.rs12
-rw-r--r--src/tools/miri/tests/fail/shims/isolated_stdin.stderr (renamed from src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr)11
-rw-r--r--src/tools/miri/tests/many-seeds/reentrant-lock.rs19
-rw-r--r--src/tools/miri/tests/panic/transmute_fat2.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs51
-rw-r--r--src/tools/miri/tests/pass-dep/shims/windows-fs.rs97
-rw-r--r--src/tools/miri/tests/pass/atomic.rs40
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs10
-rw-r--r--src/tools/miri/tests/pass/shims/io.rs8
-rw-r--r--src/tools/miri/tests/pass/shims/io.stderr1
-rw-r--r--src/tools/miri/tests/pass/shims/io.stdout1
-rw-r--r--src/tools/opt-dist/src/bolt.rs2
-rw-r--r--src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml4
-rw-r--r--src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md2
-rw-r--r--src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md8
-rw-r--r--src/tools/rust-analyzer/.github/workflows/metrics.yaml12
-rw-r--r--src/tools/rust-analyzer/Cargo.lock143
-rw-r--r--src/tools/rust-analyzer/Cargo.toml15
-rw-r--r--src/tools/rust-analyzer/crates/base-db/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs172
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs109
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs101
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs148
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs152
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/test_db.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs51
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs35
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs179
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs52
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs190
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs156
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs67
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/documentation.rs83
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs332
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs104
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs118
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs109
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs68
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs67
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs122
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs17
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tests.rs117
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast37
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs3
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs3
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs42
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs47
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs42
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs5
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs270
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs43
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/env.rs1
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs205
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs5
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs51
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs61
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs3
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs36
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs52
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json6
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml2
-rw-r--r--src/tools/rustbook/Cargo.lock53
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--tests/assembly/asm/aarch64-types.rs7
-rw-r--r--tests/codegen/autodiff/generic.rs42
-rw-r--r--tests/codegen/frame-pointer.rs4
-rw-r--r--tests/coverage/async_closure.cov-map21
-rw-r--r--tests/coverage/unused-local-file.coverage7
-rw-r--r--tests/coverage/unused-local-file.rs22
-rw-r--r--tests/crashes/113379.rs7
-rw-r--r--tests/crashes/121623.rs8
-rw-r--r--tests/crashes/122704.rs14
-rw-r--r--tests/crashes/133199.rs11
-rw-r--r--tests/crashes/136894.rs8
-rw-r--r--tests/crashes/137813.rs18
-rw-r--r--tests/crashes/139905.rs6
-rw-r--r--tests/crashes/140011.rs11
-rw-r--r--tests/crashes/140099.rs6
-rw-r--r--tests/crashes/140100.rs7
-rw-r--r--tests/crashes/140123-2.rs12
-rw-r--r--tests/crashes/140123-3.rs10
-rw-r--r--tests/crashes/140123-4.rs13
-rw-r--r--tests/crashes/140123.rs10
-rw-r--r--tests/crashes/140255.rs3
-rw-r--r--tests/crashes/140275.rs5
-rw-r--r--tests/crashes/140281.rs18
-rw-r--r--tests/crashes/140303.rs22
-rw-r--r--tests/crashes/140333.rs9
-rw-r--r--tests/crashes/140365.rs8
-rw-r--r--tests/crashes/140381.rs16
-rw-r--r--tests/crashes/140429.rs6
-rw-r--r--tests/crashes/140479.rs5
-rw-r--r--tests/crashes/140484.rs14
-rw-r--r--tests/crashes/140500.rs14
-rw-r--r--tests/crashes/140530.rs8
-rw-r--r--tests/crashes/140531.rs7
-rw-r--r--tests/crashes/140571.rs14
-rw-r--r--tests/crashes/140577.rs32
-rw-r--r--tests/crashes/140609.rs13
-rw-r--r--tests/crashes/140683.rs5
-rw-r--r--tests/crashes/140729.rs11
-rw-r--r--tests/crashes/140850.rs7
-rw-r--r--tests/crashes/140860.rs10
-rw-r--r--tests/crashes/140891.rs6
-rw-r--r--tests/crashes/141124.rs16
-rw-r--r--tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir36
-rw-r--r--tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir4
-rw-r--r--tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff2
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff2
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff4
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff4
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff4
-rw-r--r--tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.rs9
-rw-r--r--tests/pretty/autodiff/autodiff_forward.pp14
-rw-r--r--tests/pretty/autodiff/autodiff_forward.rs6
-rw-r--r--tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs12
-rw-r--r--tests/rustdoc-gui/collapse-trait-impl.goml26
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs1
-rw-r--r--tests/rustdoc-js/auxiliary/interner.rs8
-rw-r--r--tests/rustdoc-js/looks-like-rustc-interner.js6
-rw-r--r--tests/rustdoc-json/attrs/inline.rs11
-rw-r--r--tests/rustdoc-json/attrs/repr_combination.rs4
-rw-r--r--tests/rustdoc-json/attrs/repr_transparent.rs37
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr8
-rw-r--r--tests/rustdoc-ui/doctest/main-alongside-stmts.stderr14
-rw-r--r--tests/rustdoc-ui/doctest/test-main-alongside-exprs.stderr8
-rw-r--r--tests/rustdoc-ui/doctest/warn-main-not-called.rs22
-rw-r--r--tests/rustdoc-ui/doctest/warn-main-not-called.stderr14
-rw-r--r--tests/rustdoc-ui/doctest/warn-main-not-called.stdout7
-rw-r--r--tests/rustdoc-ui/intra-doc/warning.stderr36
-rw-r--r--tests/rustdoc-ui/lints/bare-urls-limit.rs12
-rw-r--r--tests/rustdoc-ui/lints/bare-urls-limit.stderr18
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.fixed10
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.rs10
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.stderr38
-rw-r--r--tests/rustdoc-ui/unescaped_backticks.stderr8
-rw-r--r--tests/ui/asm/aarch64/parse-error.rs107
-rw-r--r--tests/ui/asm/aarch64/parse-error.stderr370
-rw-r--r--tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr18
-rw-r--r--tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr8
-rw-r--r--tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr7
-rw-r--r--tests/ui/associated-item/associated-item-duplicate-names-3.stderr8
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr17
-rw-r--r--tests/ui/associated-types/associated-types-in-ambiguous-context.stderr16
-rw-r--r--tests/ui/async-await/async-closures/async-fn-mut-impl-fn-once.rs15
-rw-r--r--tests/ui/async-await/async-drop/dependency-dropped.rs5
-rw-r--r--tests/ui/async-await/async-drop/dependency-dropped.with_feature.run.stdout (renamed from tests/ui/async-await/async-drop/dependency-dropped.run.stdout)0
-rw-r--r--tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout1
-rw-r--r--tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr10
-rw-r--r--tests/ui/async-await/async-drop/deref-later-projection.rs26
-rw-r--r--tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs17
-rw-r--r--tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr11
-rw-r--r--tests/ui/async-await/async-drop/open-drop-error2.rs21
-rw-r--r--tests/ui/async-await/async-drop/open-drop-error2.stderr19
-rw-r--r--tests/ui/async-await/dyn/mut-is-pointer-like.stderr28
-rw-r--r--tests/ui/async-await/dyn/works.stderr36
-rw-r--r--tests/ui/async-await/format-await-send.rs24
-rw-r--r--tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs24
-rw-r--r--tests/ui/attributes/use-doc-alias-name.rs67
-rw-r--r--tests/ui/attributes/use-doc-alias-name.stderr150
-rw-r--r--tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs22
-rw-r--r--tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr119
-rw-r--r--tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs11
-rw-r--r--tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr17
-rw-r--r--tests/ui/check-cfg/wrong-version-syntax.fixed14
-rw-r--r--tests/ui/check-cfg/wrong-version-syntax.rs14
-rw-r--r--tests/ui/check-cfg/wrong-version-syntax.stderr17
-rw-r--r--tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs24
-rw-r--r--tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr17
-rw-r--r--tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs26
-rw-r--r--tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr39
-rw-r--r--tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs (renamed from tests/crashes/auxiliary/aux133199.rs)4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs10
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr19
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dependence_lint.rs3
-rw-r--r--tests/ui/const-generics/generic_const_exprs/different-fn.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr21
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr19
-rw-r--r--tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs16
-rw-r--r--tests/ui/const-generics/issues/issue-71202.rs4
-rw-r--r--tests/ui/const-generics/issues/issue-71202.stderr46
-rw-r--r--tests/ui/const-generics/issues/issue-83765.rs16
-rw-r--r--tests/ui/const-generics/issues/issue-83765.stderr174
-rw-r--r--tests/ui/const-generics/mgca/projection-error.rs17
-rw-r--r--tests/ui/const-generics/mgca/projection-error.stderr39
-rw-r--r--tests/ui/consts/const-eval/raw-pointer-ub.rs2
-rw-r--r--tests/ui/consts/const-eval/raw-pointer-ub.stderr4
-rw-r--r--tests/ui/consts/copy-intrinsic.rs20
-rw-r--r--tests/ui/consts/copy-intrinsic.stderr8
-rw-r--r--tests/ui/consts/missing_span_in_backtrace.stderr4
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr63
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs6
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr48
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.fixed41
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.stderr96
-rw-r--r--tests/ui/drop/drop-order-comparisons.rs41
-rw-r--r--tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs1
-rw-r--r--tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr20
-rw-r--r--tests/ui/error-codes/E0038.rs2
-rw-r--r--tests/ui/error-codes/E0038.stderr31
-rw-r--r--tests/ui/error-codes/E0223.stderr8
-rw-r--r--tests/ui/extern/extern-empty-string-issue-140884.rs3
-rw-r--r--tests/ui/extern/extern-empty-string-issue-140884.stderr15
-rw-r--r--tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr34
-rw-r--r--tests/ui/fn/coerce-suggestion-infer-region.rs26
-rw-r--r--tests/ui/fn/coerce-suggestion-infer-region.stderr12
-rw-r--r--tests/ui/generic-associated-types/trait-objects.rs2
-rw-r--r--tests/ui/generic-associated-types/trait-objects.stderr34
-rw-r--r--tests/ui/impl-trait/in-trait/dyn-compatibility.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/dyn-compatibility.stderr36
-rw-r--r--tests/ui/impl-trait/in-trait/not-inferred-generic.rs13
-rw-r--r--tests/ui/impl-trait/in-trait/not-inferred-generic.stderr21
-rw-r--r--tests/ui/impl-trait/issues/issue-100075-2.stderr15
-rw-r--r--tests/ui/impl-trait/issues/issue-100075.stderr5
-rw-r--r--tests/ui/impl-trait/issues/issue-103599.rs5
-rw-r--r--tests/ui/impl-trait/issues/issue-103599.stderr13
-rw-r--r--tests/ui/impl-trait/issues/issue-87450.rs4
-rw-r--r--tests/ui/impl-trait/issues/issue-87450.stderr18
-rw-r--r--tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr73
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr53
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr18
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.rs6
-rw-r--r--tests/ui/issues/issue-18959.rs1
-rw-r--r--tests/ui/issues/issue-18959.stderr22
-rw-r--r--tests/ui/label/continue-pointing-to-block-ice-113379.rs12
-rw-r--r--tests/ui/label/continue-pointing-to-block-ice-113379.stderr43
-rw-r--r--tests/ui/label/continue-pointing-to-block-ice-121623.rs11
-rw-r--r--tests/ui/label/continue-pointing-to-block-ice-121623.stderr14
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.rs2
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.stderr20
-rw-r--r--tests/ui/lint/bare-trait-objects-path.stderr8
-rw-r--r--tests/ui/mir/mir_match_guard_let_chains_drop_order.rs110
-rw-r--r--tests/ui/mismatched_types/hr-projection-mismatch.current.stderr12
-rw-r--r--tests/ui/mismatched_types/hr-projection-mismatch.next.stderr20
-rw-r--r--tests/ui/mismatched_types/hr-projection-mismatch.rs25
-rw-r--r--tests/ui/on-unimplemented/bad-annotation.rs12
-rw-r--r--tests/ui/on-unimplemented/bad-annotation.stderr14
-rw-r--r--tests/ui/on-unimplemented/on-trait.rs2
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs15
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs12
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr48
-rw-r--r--tests/ui/pattern/unused-parameters-const-pattern.rs19
-rw-r--r--tests/ui/qualified/qualified-path-params-2.stderr2
-rw-r--r--tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs72
-rw-r--r--tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr15
-rw-r--r--tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs64
-rw-r--r--tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr12
-rw-r--r--tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs65
-rw-r--r--tests/ui/repeat-expr/copy-check-inference-side-effects.rs34
-rw-r--r--tests/ui/repeat-expr/copy-check-inference-side-effects.stderr28
-rw-r--r--tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs9
-rw-r--r--tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr17
-rw-r--r--tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs15
-rw-r--r--tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr48
-rw-r--r--tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr12
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs29
-rw-r--r--tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs18
-rw-r--r--tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr49
-rw-r--r--tests/ui/self/self-impl.stderr16
-rw-r--r--tests/ui/structs/struct-path-associated-type.stderr24
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs14
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr31
-rw-r--r--tests/ui/traits/item-privacy.stderr16
-rw-r--r--tests/ui/traits/next-solver/assembly/better_any-backcompat.rs33
-rw-r--r--tests/ui/traits/next-solver/coercion/coerce-ambig-alias-to-rigid-alias.rs (renamed from tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/coerce-depth.rs (renamed from tests/ui/traits/next-solver/coerce-depth.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs16
-rw-r--r--tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs (renamed from tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr (renamed from tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr)0
-rw-r--r--tests/ui/traits/next-solver/coercion/trait-upcast-lhs-needs-normalization.rs (renamed from tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/upcast-right-substs.rs (renamed from tests/ui/traits/next-solver/upcast-right-substs.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/upcast-wrong-substs.rs (renamed from tests/ui/traits/next-solver/upcast-wrong-substs.rs)0
-rw-r--r--tests/ui/traits/next-solver/coercion/upcast-wrong-substs.stderr (renamed from tests/ui/traits/next-solver/upcast-wrong-substs.stderr)0
-rw-r--r--tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs29
-rw-r--r--tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs17
-rw-r--r--tests/ui/traits/next-solver/no-param-env-const-fold.rs10
-rw-r--r--tests/ui/traits/test-2.rs1
-rw-r--r--tests/ui/traits/test-2.stderr25
-rw-r--r--tests/ui/transmute/unnecessary-transmutation.fixed30
-rw-r--r--tests/ui/transmute/unnecessary-transmutation.rs24
-rw-r--r--tests/ui/transmute/unnecessary-transmutation.stderr117
-rw-r--r--tests/ui/type-alias-impl-trait/in-where-clause.stderr5
-rw-r--r--tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs (renamed from tests/crashes/139817.rs)6
-rw-r--r--tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-fn-tait.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr11
-rw-r--r--tests/ui/typeck/closure-ty-mismatch-issue-128561.rs10
-rw-r--r--tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr28
-rw-r--r--tests/ui/typeck/ice-unexpected-region-123863.stderr2
-rw-r--r--tests/ui/typeck/issue-107087.stderr8
-rw-r--r--tests/ui/unsafe-binders/non-strucutral-type-diag.rs17
-rw-r--r--tests/ui/unsafe-binders/non-strucutral-type-diag.stderr13
-rw-r--r--triagebot.toml15
1094 files changed, 19124 insertions, 11553 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 93316b9cff7..566ae223500 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -73,6 +73,15 @@ jobs:
     needs: [ calculate_matrix ]
     runs-on: "${{ matrix.os }}"
     timeout-minutes: 360
+    # The bors environment contains secrets required for elevated workflows (try and auto builds),
+    # which need to access e.g. S3 and upload artifacts. We want to provide access to that
+    # environment only on the try/auto branches, which are only accessible to bors.
+    # This also ensures that PR CI (which doesn't get write access to S3) works, as it cannot
+    # access the environment.
+    #
+    # We only enable the environment for the rust-lang/rust repository, so that rust-lang-ci/rust
+    # CI works until we migrate off it (since that repository doesn't contain the environment).
+    environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }}
     env:
       CI_JOB_NAME: ${{ matrix.name }}
       CI_JOB_DOC_URL: ${{ matrix.doc_url }}
@@ -225,8 +234,8 @@ jobs:
           fi
           exit ${STATUS}
         env:
-          AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
-          AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
+          AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_ACCESS_KEY_ID) || env.CACHES_AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.CACHES_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
 
       - name: create github artifacts
         run: src/ci/scripts/create-doc-artifacts.sh
@@ -248,8 +257,8 @@ jobs:
       - name: upload artifacts to S3
         run: src/ci/scripts/upload-artifacts.sh
         env:
-          AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
-          AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
+          AWS_ACCESS_KEY_ID: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_ACCESS_KEY_ID) || env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY: ${{ (github.repository == 'rust-lang/rust' && secrets.ARTIFACTS_AWS_SECRET_ACCESS_KEY) || secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
         # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy
         # builders *should* have the AWS credentials available. Still, explicitly
         # adding the condition is helpful as this way CI will not silently skip
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e155e253784..aadc7c48ea8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,7 +5,7 @@ and we appreciate all of them.
 
 The best way to get started is by asking for help in the [#new
 members](https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members)
-Zulip stream. We have lots of docs below of how to get started on your own, but
+Zulip stream. We have a lot of documentation below on how to get started on your own, but
 the Zulip stream is the best place to *ask* for help.
 
 Documentation for contributing to the compiler or tooling is located in the [Guide to Rustc
@@ -14,7 +14,7 @@ standard library in the [Standard library developers Guide][std-dev-guide], comm
 
 ## Making changes to subtrees and submodules
 
-For submodules, changes need to be made against the repository corresponding the
+For submodules, changes need to be made against the repository corresponding to the
 submodule, and not the main `rust-lang/rust` repository.
 
 For subtrees, prefer sending a PR against the subtree's repository if it does
@@ -25,7 +25,7 @@ rustc-dev-guide change that does not accompany a compiler change).
 
 The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works,
 as well as to help new contributors get involved in rustc development. It is recommended
-to read and understand the [rustc-dev-guide] before making a contribution. This guide
+that you read and understand the [rustc-dev-guide] before making a contribution. This guide
 talks about the different bots in the Rust ecosystem, the Rust development tools,
 bootstrapping, the compiler architecture, source code representation, and more.
 
@@ -33,7 +33,7 @@ bootstrapping, the compiler architecture, source code representation, and more.
 
 There are many ways you can get help when you're stuck. Rust has many platforms for this:
 [internals], [rust-zulip], and [rust-discord]. It is recommended to ask for help on
-the [rust-zulip], but any of these platforms are a great way to seek help and even
+the [rust-zulip], but any of these platforms are great ways to seek help and even
 find a mentor! You can learn more about asking questions and getting help in the
 [Asking Questions](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) chapter of the [rustc-dev-guide].
 
diff --git a/Cargo.lock b/Cargo.lock
index 59f7f3dda8f..4e5040349e0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -582,13 +582,11 @@ dependencies = [
 name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
- "aho-corasick",
  "chrono",
  "clap",
  "indoc",
  "itertools",
  "opener",
- "shell-escape",
  "walkdir",
 ]
 
@@ -3118,9 +3116,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.5"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb332121f7845c6bd016f9655cf22f03c2999df936694b624a88669a78667d98"
+checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -3390,6 +3388,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -3424,7 +3423,7 @@ dependencies = [
  "rustc-demangle",
  "rustc_abi",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_codegen_ssa",
  "rustc_data_structures",
  "rustc_errors",
@@ -3467,6 +3466,7 @@ dependencies = [
  "rustc_abi",
  "rustc_arena",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -3504,7 +3504,7 @@ dependencies = [
  "rustc_abi",
  "rustc_apfloat",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -3680,6 +3680,7 @@ dependencies = [
  "rustc_ast",
  "rustc_ast_passes",
  "rustc_ast_pretty",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -3768,7 +3769,7 @@ dependencies = [
  "rustc_abi",
  "rustc_arena",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
@@ -3805,6 +3806,7 @@ dependencies = [
  "itertools",
  "rustc_abi",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -3950,6 +3952,7 @@ dependencies = [
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -4023,6 +4026,7 @@ dependencies = [
  "odht",
  "rustc_abi",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
@@ -4136,7 +4140,7 @@ dependencies = [
  "rustc_abi",
  "rustc_arena",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_const_eval",
  "rustc_data_structures",
  "rustc_errors",
@@ -4162,7 +4166,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_abi",
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -4232,7 +4236,7 @@ dependencies = [
  "rustc_ast",
  "rustc_ast_lowering",
  "rustc_ast_pretty",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
@@ -4278,7 +4282,7 @@ name = "rustc_privacy"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
- "rustc_attr_parsing",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -4883,12 +4887,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "shell-escape"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
-
-[[package]]
 name = "shlex"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 89a5a67eb53..4fc7c7475d7 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
+#![feature(macro_metavar_expr)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(rustdoc_internals)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index e49886721e3..a90349f318c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -20,7 +20,7 @@ use thin_vec::ThinVec;
 use crate::ast::*;
 use crate::ptr::P;
 use crate::tokenstream::*;
-use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
+use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit};
 
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
@@ -388,6 +388,8 @@ pub trait MutVisitor: Sized {
     }
 }
 
+super::common_visitor_and_walkers!((mut) MutVisitor);
+
 /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
 /// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
 /// method.
@@ -778,15 +780,6 @@ fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness)
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_safety<T: MutVisitor>(vis: &mut T, safety: &mut Safety) {
-    match safety {
-        Safety::Unsafe(span) => vis.visit_span(span),
-        Safety::Safe(span) => vis.visit_span(span),
-        Safety::Default => {}
-    }
-}
-
-// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 fn visit_polarity<T: MutVisitor>(vis: &mut T, polarity: &mut ImplPolarity) {
     match polarity {
         ImplPolarity::Positive => {}
@@ -794,14 +787,6 @@ fn visit_polarity<T: MutVisitor>(vis: &mut T, polarity: &mut ImplPolarity) {
     }
 }
 
-// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_constness<T: MutVisitor>(vis: &mut T, constness: &mut Const) {
-    match constness {
-        Const::Yes(span) => vis.visit_span(span),
-        Const::No => {}
-    }
-}
-
 fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
     match binder {
         ClosureBinder::NotPresent => {}
@@ -940,15 +925,6 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
     smallvec![param]
 }
 
-fn walk_label<T: MutVisitor>(vis: &mut T, Label { ident }: &mut Label) {
-    vis.visit_ident(ident);
-}
-
-fn walk_lifetime<T: MutVisitor>(vis: &mut T, Lifetime { id, ident }: &mut Lifetime) {
-    vis.visit_id(id);
-    vis.visit_ident(ident);
-}
-
 fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) {
     let Generics { params, where_clause, span } = generics;
     params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
@@ -1340,13 +1316,6 @@ fn walk_const_item<T: MutVisitor>(vis: &mut T, item: &mut ConstItem) {
     walk_define_opaques(vis, define_opaque);
 }
 
-fn walk_fn_header<T: MutVisitor>(vis: &mut T, header: &mut FnHeader) {
-    let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
-    visit_constness(vis, constness);
-    coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
-    visit_safety(vis, safety);
-}
-
 pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
     let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
     vis.visit_id(id);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 69a186c8cf1..e43d7ae065d 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -315,6 +315,75 @@ pub trait Visitor<'ast>: Sized {
     }
 }
 
+#[macro_export]
+macro_rules! common_visitor_and_walkers {
+    ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => {
+        // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
+        $(${ignore($lt)}
+            #[expect(unused, rustc::pass_by_value)]
+            #[inline]
+        )?
+        fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> <V as Visitor<$lt>>::Result)? {
+            $(
+                let _ = stringify!($mut);
+                visitor.visit_span(span);
+            )?
+            $(${ignore($lt)}V::Result::output())?
+        }
+
+        // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
+        $(${ignore($lt)}
+            #[expect(unused, rustc::pass_by_value)]
+            #[inline]
+        )?
+        fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> <V as Visitor<$lt>>::Result)? {
+            $(
+                let _ = stringify!($mut);
+                visitor.visit_id(id);
+            )?
+            $(${ignore($lt)}V::Result::output())?
+        }
+
+        // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
+        fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) $(-> <V as Visitor<$lt>>::Result)? {
+            match safety {
+                Safety::Unsafe(span) => visit_span(vis, span),
+                Safety::Safe(span) => visit_span(vis, span),
+                Safety::Default => { $(${ignore($lt)}V::Result::output())? }
+            }
+        }
+
+        fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) $(-> <V as Visitor<$lt>>::Result)? {
+            match constness {
+                Const::Yes(span) => visit_span(vis, span),
+                Const::No => {
+                    $(<V as Visitor<$lt>>::Result::output())?
+                }
+            }
+        }
+
+        pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> <V as Visitor<$lt>>::Result)? {
+            visitor.visit_ident(ident)
+        }
+
+        pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) $(-> <V as Visitor<$lt>>::Result)? {
+            let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
+            try_visit!(visit_constness(visitor, constness));
+            if let Some(coroutine_kind) = coroutine_kind {
+                try_visit!(visitor.visit_coroutine_kind(coroutine_kind));
+            }
+            visit_safety(visitor, safety)
+        }
+
+        pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) $(-> <V as Visitor<$lt>>::Result)? {
+            try_visit!(visit_id(visitor, id));
+            visitor.visit_ident(ident)
+        }
+    };
+}
+
+common_visitor_and_walkers!(Visitor<'a>);
+
 pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
     let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate;
     walk_list!(visitor, visit_attribute, attrs);
@@ -334,15 +403,6 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R
     V::Result::output()
 }
 
-pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result {
-    visitor.visit_ident(ident)
-}
-
-pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result {
-    let Lifetime { id: _, ident } = lifetime;
-    visitor.visit_ident(ident)
-}
-
 pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result
 where
     V: Visitor<'a>,
@@ -926,12 +986,6 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy)
     V::Result::output()
 }
 
-pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result {
-    let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header;
-    visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
-    V::Result::output()
-}
-
 pub fn walk_fn_decl<'a, V: Visitor<'a>>(
     visitor: &mut V,
     FnDecl { inputs, output }: &'a FnDecl,
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 0de0319c667..17b443b8ecc 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -6,7 +6,7 @@ use rustc_ast::*;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_session::config::FmtDebug;
-use rustc_span::{Ident, Span, Symbol, kw, sym};
+use rustc_span::{Ident, Span, Symbol, sym};
 
 use super::LoweringContext;
 
@@ -418,7 +418,7 @@ fn expand_format_args<'hir>(
                 &FormatArgsPiece::Placeholder(_) => {
                     // Inject empty string before placeholders when not already preceded by a literal piece.
                     if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
-                        Some(ctx.expr_str(fmt.span, kw::Empty))
+                        Some(ctx.expr_str(fmt.span, sym::empty))
                     } else {
                         None
                     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index f48a571b86a..e98d6c50ee7 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -70,44 +70,32 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
         }
     }
 
-    pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> {
+    pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
         let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
         if let hir::MaybeOwner::Phantom = owner {
             let node = self.ast_index[def_id];
             match node {
                 AstOwner::NonOwner => {}
-                AstOwner::Crate(c) => self.lower_crate(c),
-                AstOwner::Item(item) => self.lower_item(item),
-                AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
-                AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
+                AstOwner::Crate(c) => {
+                    debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
+                    self.with_lctx(CRATE_NODE_ID, |lctx| {
+                        let module = lctx.lower_mod(&c.items, &c.spans);
+                        // FIXME(jdonszelman): is dummy span ever a problem here?
+                        lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP);
+                        hir::OwnerNode::Crate(module)
+                    })
+                }
+                AstOwner::Item(item) => {
+                    self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
+                }
+                AstOwner::AssocItem(item, ctxt) => {
+                    self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt))
+                }
+                AstOwner::ForeignItem(item) => self.with_lctx(item.id, |lctx| {
+                    hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
+                }),
             }
         }
-
-        self.owners[def_id]
-    }
-
-    #[instrument(level = "debug", skip(self, c))]
-    fn lower_crate(&mut self, c: &Crate) {
-        debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
-        self.with_lctx(CRATE_NODE_ID, |lctx| {
-            let module = lctx.lower_mod(&c.items, &c.spans);
-            // FIXME(jdonszelman): is dummy span ever a problem here?
-            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP);
-            hir::OwnerNode::Crate(module)
-        })
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn lower_item(&mut self, item: &Item) {
-        self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
-    }
-
-    fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
-        self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt))
-    }
-
-    fn lower_foreign_item(&mut self, item: &ForeignItem) {
-        self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 19095f2e01e..422e79ca82f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -444,14 +444,14 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
         tcx.definitions_untracked().def_index_count(),
     );
 
+    let mut lowerer = item::ItemLowerer {
+        tcx,
+        resolver: &mut resolver,
+        ast_index: &ast_index,
+        owners: &mut owners,
+    };
     for def_id in ast_index.indices() {
-        item::ItemLowerer {
-            tcx,
-            resolver: &mut resolver,
-            ast_index: &ast_index,
-            owners: &mut owners,
-        }
-        .lower_node(def_id);
+        lowerer.lower_node(def_id);
     }
 
     drop(ast_index);
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 05a9029c59a..503d2f1fae1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -26,3 +26,33 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
 pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
     first_attr_value_str_by_name(attrs, sym::crate_name)
 }
+
+pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
+    attrs: impl Iterator<Item = &'tcx T>,
+    symbol: Symbol,
+) -> bool {
+    let doc_attrs = attrs.filter(|attr| attr.has_name(sym::doc));
+    for attr in doc_attrs {
+        let Some(values) = attr.meta_item_list() else {
+            continue;
+        };
+        let alias_values = values.iter().filter(|v| v.has_name(sym::alias));
+        for v in alias_values {
+            if let Some(nested) = v.meta_item_list() {
+                // #[doc(alias("foo", "bar"))]
+                let mut iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
+                if iter.any(|s| s == symbol) {
+                    return true;
+                }
+            } else if let Some(meta) = v.meta_item()
+                && let Some(lit) = meta.name_value_literal()
+            {
+                // #[doc(alias = "foo")]
+                if lit.symbol == symbol {
+                    return true;
+                }
+            }
+        }
+    }
+    false
+}
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 177df356742..63bccf52018 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -60,7 +60,8 @@
 //! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define
 //! a "stability" of an item. So, the stability attribute has an
 //! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]`
-//! and `#[unstable()]` syntactic attributes, and at the end produce a single [`AttributeKind::Stability`].
+//! and `#[unstable()]` syntactic attributes, and at the end produce a single
+//! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability).
 //!
 //! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be
 //! combined into a single semantic attribute. For example:
@@ -89,8 +90,9 @@ pub mod parser;
 mod session_diagnostics;
 
 pub use attributes::cfg::*;
-pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version};
+pub use attributes::util::{
+    find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
+};
 pub use context::{AttributeParser, OmitDoc};
-pub use rustc_attr_data_structures::*;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 92732aba29b..f642d34ea67 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -131,7 +131,8 @@ impl UniversalRegionRelations<'_> {
         assert!(self.universal_regions.is_universal_region(fr0));
 
         let mut external_parents = vec![];
-        let mut queue = vec![fr0];
+
+        let mut queue = vec![relation.minimal_scc_representative(fr0)];
 
         // Keep expanding `fr` into its parents until we reach
         // non-local regions.
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 1289d21308b..5c1ae90f729 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -10,6 +10,7 @@ doctest = false
 # tidy-alphabetical-start
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 8c5c20c7af4..1ff4fc6aaab 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -73,10 +73,10 @@ mod llvm_enzyme {
     }
 
     // Get information about the function the macro is applied to
-    fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident)> {
+    fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident, Generics)> {
         match &iitem.kind {
-            ItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
-                Some((iitem.vis.clone(), sig.clone(), ident.clone()))
+            ItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => {
+                Some((iitem.vis.clone(), sig.clone(), ident.clone(), generics.clone()))
             }
             _ => None,
         }
@@ -210,16 +210,18 @@ mod llvm_enzyme {
         }
         let dcx = ecx.sess.dcx();
 
-        // first get information about the annotable item:
-        let Some((vis, sig, primal)) = (match &item {
+        // first get information about the annotable item: visibility, signature, name and generic
+        // parameters.
+        // these will be used to generate the differentiated version of the function
+        let Some((vis, sig, primal, generics)) = (match &item {
             Annotatable::Item(iitem) => extract_item_info(iitem),
             Annotatable::Stmt(stmt) => match &stmt.kind {
                 ast::StmtKind::Item(iitem) => extract_item_info(iitem),
                 _ => None,
             },
             Annotatable::AssocItem(assoc_item, Impl { .. }) => match &assoc_item.kind {
-                ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
-                    Some((assoc_item.vis.clone(), sig.clone(), ident.clone()))
+                ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => {
+                    Some((assoc_item.vis.clone(), sig.clone(), ident.clone(), generics.clone()))
                 }
                 _ => None,
             },
@@ -303,6 +305,7 @@ mod llvm_enzyme {
         let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span);
         let d_body = gen_enzyme_body(
             ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored,
+            &generics,
         );
 
         // The first element of it is the name of the function to be generated
@@ -310,7 +313,7 @@ mod llvm_enzyme {
             defaultness: ast::Defaultness::Final,
             sig: d_sig,
             ident: first_ident(&meta_item_vec[0]),
-            generics: Generics::default(),
+            generics,
             contract: None,
             body: Some(d_body),
             define_opaque: None,
@@ -475,6 +478,7 @@ mod llvm_enzyme {
         new_decl_span: Span,
         idents: &[Ident],
         errored: bool,
+        generics: &Generics,
     ) -> (P<ast::Block>, P<ast::Expr>, P<ast::Expr>, P<ast::Expr>) {
         let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]);
         let noop = ast::InlineAsm {
@@ -497,7 +501,7 @@ mod llvm_enzyme {
         };
         let unsf_expr = ecx.expr_block(P(unsf_block));
         let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path));
-        let primal_call = gen_primal_call(ecx, span, primal, idents);
+        let primal_call = gen_primal_call(ecx, span, primal, idents, generics);
         let black_box_primal_call = ecx.expr_call(
             new_decl_span,
             blackbox_call_expr.clone(),
@@ -546,6 +550,7 @@ mod llvm_enzyme {
         sig_span: Span,
         idents: Vec<Ident>,
         errored: bool,
+        generics: &Generics,
     ) -> P<ast::Block> {
         let new_decl_span = d_sig.span;
 
@@ -566,6 +571,7 @@ mod llvm_enzyme {
             new_decl_span,
             &idents,
             errored,
+            generics,
         );
 
         if !has_ret(&d_sig.decl.output) {
@@ -608,7 +614,6 @@ mod llvm_enzyme {
                 panic!("Did not expect Default ret ty: {:?}", span);
             }
         };
-
         if x.mode.is_fwd() {
             // Fwd mode is easy. If the return activity is Const, we support arbitrary types.
             // Otherwise, we only support a scalar, a pair of scalars, or an array of scalars.
@@ -668,8 +673,10 @@ mod llvm_enzyme {
         span: Span,
         primal: Ident,
         idents: &[Ident],
+        generics: &Generics,
     ) -> P<ast::Expr> {
         let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower;
+
         if has_self {
             let args: ThinVec<_> =
                 idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
@@ -678,7 +685,51 @@ mod llvm_enzyme {
         } else {
             let args: ThinVec<_> =
                 idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
-            let primal_call_expr = ecx.expr_path(ecx.path_ident(span, primal));
+            let mut primal_path = ecx.path_ident(span, primal);
+
+            let is_generic = !generics.params.is_empty();
+
+            match (is_generic, primal_path.segments.last_mut()) {
+                (true, Some(function_path)) => {
+                    let primal_generic_types = generics
+                        .params
+                        .iter()
+                        .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }));
+
+                    let generated_generic_types = primal_generic_types
+                        .map(|type_param| {
+                            let generic_param = TyKind::Path(
+                                None,
+                                ast::Path {
+                                    span,
+                                    segments: thin_vec![ast::PathSegment {
+                                        ident: type_param.ident,
+                                        args: None,
+                                        id: ast::DUMMY_NODE_ID,
+                                    }],
+                                    tokens: None,
+                                },
+                            );
+
+                            ast::AngleBracketedArg::Arg(ast::GenericArg::Type(P(ast::Ty {
+                                id: type_param.id,
+                                span,
+                                kind: generic_param,
+                                tokens: None,
+                            })))
+                        })
+                        .collect();
+
+                    function_path.args =
+                        Some(P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs {
+                            span,
+                            args: generated_generic_types,
+                        })));
+                }
+                _ => {}
+            }
+
+            let primal_call_expr = ecx.expr_path(primal_path);
             ecx.expr_call(span, primal_call_expr, args)
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index d9aac54ee73..9aa53f9e4f7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -185,7 +185,8 @@ use rustc_ast::{
     self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
     Generics, Mutability, PatKind, VariantData,
 };
-use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked};
+use rustc_attr_data_structures::{AttributeKind, ReprPacked};
+use rustc_attr_parsing::AttributeParser;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_hir::Attribute;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
index 16c8488acdb..f6e6bbc2387 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot_tests-128bit-atomic-operations.patch
@@ -17,7 +17,7 @@ index 1e336bf..35e6f54 100644
 @@ -2,5 +2,4 @@
  // tidy-alphabetical-start
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
- #![cfg_attr(test, feature(cfg_match))]
+ #![cfg_attr(test, feature(cfg_select))]
  #![feature(alloc_layout_extra)]
  #![feature(array_chunks)]
 diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index e63091c6082..c853c88a6ea 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -2,8 +2,8 @@
 use gccjit::FnAttribute;
 use gccjit::Function;
 #[cfg(feature = "master")]
-use rustc_attr_parsing::InlineAttr;
-use rustc_attr_parsing::InstructionSetAttr;
+use rustc_attr_data_structures::InlineAttr;
+use rustc_attr_data_structures::InstructionSetAttr;
 #[cfg(feature = "master")]
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 #[cfg(feature = "master")]
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index c133ae4fcdd..c8130b7c010 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -106,7 +106,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
                 // This is a monomorphization of a generic function.
                 if !(cx.tcx.sess.opts.share_generics()
                     || tcx.codegen_fn_attrs(instance_def_id).inline
-                        == rustc_attr_parsing::InlineAttr::Never)
+                        == rustc_attr_data_structures::InlineAttr::Never)
                 {
                     // When not sharing generics, all instances are in the same
                     // crate and have hidden visibility.
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 6e2a50d745a..6994c385fc8 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -37,7 +37,7 @@ extern crate tracing;
 extern crate rustc_abi;
 extern crate rustc_apfloat;
 extern crate rustc_ast;
-extern crate rustc_attr_parsing;
+extern crate rustc_attr_data_structures;
 extern crate rustc_codegen_ssa;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 3185993c207..bf8ec8c3b91 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -19,7 +19,7 @@ object = { version = "0.36.3", default-features = false, features = ["std", "rea
 rustc-demangle = "0.1.21"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 176fb72dfdc..443c2eace55 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -1,5 +1,5 @@
 //! Set and unset common attributes on LLVM values.
-use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_codegen_ssa::traits::*;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index ea9ab5c02bd..6d68eca60af 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -103,7 +103,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
             // This is a monomorphization of a generic function.
             if !(cx.tcx.sess.opts.share_generics()
                 || tcx.codegen_fn_attrs(instance_def_id).inline
-                    == rustc_attr_parsing::InlineAttr::Never)
+                    == rustc_attr_data_structures::InlineAttr::Never)
             {
                 // When not sharing generics, all instances are in the same
                 // crate and have hidden visibility.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index f6000e72840..c207df2fb0b 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -155,6 +155,20 @@ pub(crate) struct Regions {
 impl Regions {
     /// Returns true if none of this structure's tables contain any regions.
     pub(crate) fn has_no_regions(&self) -> bool {
+        // Every region has a span, so if there are no spans then there are no regions.
+        self.all_cov_spans().next().is_none()
+    }
+
+    pub(crate) fn all_cov_spans(&self) -> impl Iterator<Item = &CoverageSpan> {
+        macro_rules! iter_cov_spans {
+            ( $( $regions:expr ),* $(,)? ) => {
+                std::iter::empty()
+                $(
+                    .chain( $regions.iter().map(|region| &region.cov_span) )
+                )*
+            }
+        }
+
         let Self {
             code_regions,
             expansion_regions,
@@ -163,11 +177,13 @@ impl Regions {
             mcdc_decision_regions,
         } = self;
 
-        code_regions.is_empty()
-            && expansion_regions.is_empty()
-            && branch_regions.is_empty()
-            && mcdc_branch_regions.is_empty()
-            && mcdc_decision_regions.is_empty()
+        iter_cov_spans!(
+            code_regions,
+            expansion_regions,
+            branch_regions,
+            mcdc_branch_regions,
+            mcdc_decision_regions,
+        )
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 7bdbc685952..d3a815fabe7 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -11,6 +11,7 @@ use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
     BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods,
 };
+use rustc_index::IndexVec;
 use rustc_middle::mir::coverage::{
     BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
     MappingKind, Op,
@@ -104,6 +105,16 @@ fn fill_region_tables<'tcx>(
     ids_info: &'tcx CoverageIdsInfo,
     covfun: &mut CovfunRecord<'tcx>,
 ) {
+    // If this function is unused, replace all counters with zero.
+    let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
+        let term = if covfun.is_used {
+            ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
+        } else {
+            CovTerm::Zero
+        };
+        ffi::Counter::from_term(term)
+    };
+
     // Currently a function's mappings must all be in the same file, so use the
     // first mapping's span to determine the file.
     let source_map = tcx.sess.source_map();
@@ -115,6 +126,12 @@ fn fill_region_tables<'tcx>(
 
     let local_file_id = covfun.virtual_file_mapping.push_file(&source_file);
 
+    // If this testing flag is set, add an extra unused entry to the local
+    // file table, to help test the code for detecting unused file IDs.
+    if tcx.sess.coverage_inject_unused_local_file() {
+        covfun.virtual_file_mapping.push_file(&source_file);
+    }
+
     // In rare cases, _all_ of a function's spans are discarded, and coverage
     // codegen needs to handle that gracefully to avoid #133606.
     // It's hard for tests to trigger this organically, so instead we set
@@ -135,16 +152,6 @@ fn fill_region_tables<'tcx>(
     // For each counter/region pair in this function+file, convert it to a
     // form suitable for FFI.
     for &Mapping { ref kind, span } in &fn_cov_info.mappings {
-        // If this function is unused, replace all counters with zero.
-        let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
-            let term = if covfun.is_used {
-                ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
-            } else {
-                CovTerm::Zero
-            };
-            ffi::Counter::from_term(term)
-        };
-
         let Some(coords) = make_coords(span) else { continue };
         let cov_span = coords.make_coverage_span(local_file_id);
 
@@ -177,6 +184,19 @@ fn fill_region_tables<'tcx>(
     }
 }
 
+/// LLVM requires all local file IDs to have at least one mapping region.
+/// If that's not the case, skip this function, to avoid an assertion failure
+/// (or worse) in LLVM.
+fn check_local_file_table(covfun: &CovfunRecord<'_>) -> bool {
+    let mut local_file_id_seen =
+        IndexVec::<u32, _>::from_elem_n(false, covfun.virtual_file_mapping.local_file_table.len());
+    for cov_span in covfun.regions.all_cov_spans() {
+        local_file_id_seen[cov_span.file_id] = true;
+    }
+
+    local_file_id_seen.into_iter().all(|seen| seen)
+}
+
 /// Generates the contents of the covfun record for this function, which
 /// contains the function's coverage mapping data. The record is then stored
 /// as a global variable in the `__llvm_covfun` section.
@@ -185,6 +205,10 @@ pub(crate) fn generate_covfun_record<'tcx>(
     global_file_table: &GlobalFileTable,
     covfun: &CovfunRecord<'tcx>,
 ) {
+    if !check_local_file_table(covfun) {
+        return;
+    }
+
     let &CovfunRecord {
         mangled_function_name,
         source_hash,
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
index 39a59560c9d..574463be7ff 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
@@ -39,7 +39,10 @@ impl Coords {
 /// or other expansions), and if it does happen then skipping a span or function is
 /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
 pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option<Coords> {
-    let span = ensure_non_empty_span(source_map, span)?;
+    if span.is_empty() {
+        debug_assert!(false, "can't make coords from empty span: {span:?}");
+        return None;
+    }
 
     let lo = span.lo();
     let hi = span.hi();
@@ -70,29 +73,6 @@ pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span)
     })
 }
 
-fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
-    if !span.is_empty() {
-        return Some(span);
-    }
-
-    // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
-    source_map
-        .span_to_source(span, |src, start, end| try {
-            // Adjusting span endpoints by `BytePos(1)` is normally a bug,
-            // but in this case we have specifically checked that the character
-            // we're skipping over is one of two specific ASCII characters, so
-            // adjusting by exactly 1 byte is correct.
-            if src.as_bytes().get(end).copied() == Some(b'{') {
-                Some(span.with_hi(span.hi() + BytePos(1)))
-            } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
-                Some(span.with_lo(span.lo() - BytePos(1)))
-            } else {
-                None
-            }
-        })
-        .ok()?
-}
-
 /// If `llvm-cov` sees a source region that is improperly ordered (end < start),
 /// it will immediately exit with a fatal error. To prevent that from happening,
 /// discard regions that are improperly ordered, or might be interpreted in a
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index d4c8ab80a33..337c6944177 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -19,6 +19,7 @@ regex = "1.4"
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 2621935eecf..acb4cbaa13f 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -1,5 +1,7 @@
 codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
 
+codegen_ssa_aarch64_softfloat_neon = enabling the `neon` target feature on the current target is unsound due to ABI issues
+
 codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
 
 codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to AIX which is not guaranteed to work
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 5f0a0cf922a..96aec9769d2 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -370,7 +370,7 @@ fn exported_symbols_provider_local<'tcx>(
 
             if !tcx.sess.opts.share_generics() {
                 if tcx.codegen_fn_attrs(mono_item.def_id()).inline
-                    == rustc_attr_parsing::InlineAttr::Never
+                    == rustc_attr_data_structures::InlineAttr::Never
                 {
                     // this is OK, we explicitly allow sharing inline(never) across crates even
                     // without share-generics.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 775ab9071e7..1890119dca7 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
 use rustc_abi::FIRST_VARIANT;
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
-use rustc_attr_parsing::OptimizeAttr;
+use rustc_attr_data_structures::OptimizeAttr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 835ffb7d4fc..b3bda784d43 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -3,8 +3,8 @@ use std::str::FromStr;
 use rustc_abi::ExternAbi;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
-use rustc_attr_parsing::ReprAttr::ReprAlign;
-use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_attr_data_structures::ReprAttr::ReprAlign;
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -299,6 +299,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 }
                 from_target_feature_attr(
                     tcx,
+                    did,
                     attr,
                     rust_target_features,
                     &mut codegen_fn_attrs.target_features,
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index d49aac75d05..572d7b1e06a 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1316,3 +1316,7 @@ pub(crate) struct XcrunSdkPathWarning {
     pub sdk_name: &'static str,
     pub stderr: String,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(codegen_ssa_aarch64_softfloat_neon)]
+pub(crate) struct Aarch64SoftfloatNeon;
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 5924c8991ad..f731613d67e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{Instance, Ty};
 use rustc_middle::{bug, mir, ty};
 use rustc_session::config::DebugInfo;
-use rustc_span::{BytePos, Span, Symbol, hygiene, kw};
+use rustc_span::{BytePos, Span, Symbol, hygiene, sym};
 
 use super::operand::{OperandRef, OperandValue};
 use super::place::{PlaceRef, PlaceValue};
@@ -283,7 +283,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // (after #67586 gets fixed).
                 None
             } else {
-                let name = kw::Empty;
+                let name = sym::empty;
                 let decl = &self.mir.local_decls[local];
                 let dbg_var = if full_debug_info {
                     self.adjusted_span_and_dbg_scope(decl.source_info).map(
@@ -318,7 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             None
         } else {
             Some(match whole_local_var.or(fallback_var.clone()) {
-                Some(var) if var.name != kw::Empty => var.name.to_string(),
+                Some(var) if var.name != sym::empty => var.name.to_string(),
                 _ => format!("{local:?}"),
             })
         };
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index d2a687359e0..46fb9a89513 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -1,5 +1,5 @@
 use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
-use rustc_attr_parsing::InstructionSetAttr;
+use rustc_attr_data_structures::InstructionSetAttr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility};
 use rustc_middle::mir::{InlineAsmOperand, START_BLOCK};
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 8058cd1b178..6bb3150c1c5 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,4 +1,4 @@
-use rustc_attr_parsing::InstructionSetAttr;
+use rustc_attr_data_structures::InstructionSetAttr;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Applicability;
@@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
 use rustc_target::target_features::{self, Stability};
@@ -18,6 +19,7 @@ use crate::errors;
 /// Enabled target features are added to `target_features`.
 pub(crate) fn from_target_feature_attr(
     tcx: TyCtxt<'_>,
+    did: LocalDefId,
     attr: &hir::Attribute,
     rust_target_features: &UnordMap<String, target_features::Stability>,
     target_features: &mut Vec<TargetFeature>,
@@ -92,11 +94,22 @@ pub(crate) fn from_target_feature_attr(
                     // generating code so "it's fine".
                     if !tcx.sess.opts.actually_rustdoc {
                         if abi_feature_constraints.incompatible.contains(&name.as_str()) {
-                            tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
-                                span: item.span(),
-                                feature: name.as_str(),
-                                reason: "this feature is incompatible with the target ABI",
-                            });
+                            // For "neon" specifically, we emit an FCW instead of a hard error.
+                            // See <https://github.com/rust-lang/rust/issues/134375>.
+                            if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" {
+                                tcx.emit_node_span_lint(
+                                    AARCH64_SOFTFLOAT_NEON,
+                                    tcx.local_def_id_to_hir_id(did),
+                                    item.span(),
+                                    errors::Aarch64SoftfloatNeon,
+                                );
+                            } else {
+                                tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
+                                    span: item.span(),
+                                    feature: name.as_str(),
+                                    reason: "this feature is incompatible with the target ABI",
+                                });
+                            }
                         }
                     }
                     target_features.push(TargetFeature { name, implied: name != feature_sym })
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 02be8762d6f..93d0d5b9a71 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -9,7 +9,7 @@ either = "1"
 rustc_abi = { path = "../rustc_abi" }
 rustc_apfloat = "0.2.0"
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index b600b8918dd..b67a3ce03a9 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -6,7 +6,7 @@ use std::mem;
 use std::num::NonZero;
 use std::ops::Deref;
 
-use rustc_attr_parsing::{ConstStability, StabilityLevel};
+use rustc_attr_data_structures as attrs;
 use rustc_errors::{Diag, ErrorGuaranteed};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -475,7 +475,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     /// Check the const stability of the given item (fn or trait).
     fn check_callee_stability(&mut self, def_id: DefId) {
         match self.tcx.lookup_const_stability(def_id) {
-            Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
+            Some(attrs::ConstStability { level: attrs::StabilityLevel::Stable { .. }, .. }) => {
                 // All good.
             }
             None => {
@@ -491,8 +491,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                     });
                 }
             }
-            Some(ConstStability {
-                level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
+            Some(attrs::ConstStability {
+                level: attrs::StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
                 feature,
                 ..
             }) => {
@@ -918,8 +918,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 });
                             }
                         }
-                        Some(ConstStability {
-                            level: StabilityLevel::Unstable { .. },
+                        Some(attrs::ConstStability {
+                            level: attrs::StabilityLevel::Unstable { .. },
                             feature,
                             ..
                         }) => {
@@ -930,7 +930,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                                 suggestion: self.crate_inject_span(),
                             });
                         }
-                        Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
+                        Some(attrs::ConstStability {
+                            level: attrs::StabilityLevel::Stable { .. },
+                            ..
+                        }) => {
                             // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it
                             // can be *directly* invoked from stable const code) does not always
                             // have the `#[rustc_intrinsic_const_stable_indirect]` attribute (which controls
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 06ee7075170..d8421415225 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -4,13 +4,12 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
-use rustc_attr_parsing::{AttributeKind, find_attr};
 use rustc_errors::DiagCtxtHandle;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
+use {rustc_attr_data_structures as attrs, rustc_hir as hir};
 
 pub use self::qualifs::Qualif;
 
@@ -83,7 +82,7 @@ pub fn rustc_allow_const_fn_unstable(
 ) -> bool {
     let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
 
-    find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate))
+    attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate))
 }
 
 /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index a1386b4e1be..d13e17a481a 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -147,6 +147,12 @@ pub trait Machine<'tcx>: Sized {
     /// already been checked before.
     const ALL_CONSTS_ARE_PRECHECKED: bool = true;
 
+    /// Determines whether rustc_const_eval functions that make use of the [Machine] should make
+    /// tracing calls (to the `tracing` library). By default this is `false`, meaning the tracing
+    /// calls will supposedly be optimized out. This flag is set to `true` inside Miri, to allow
+    /// tracing the interpretation steps, among other things.
+    const TRACING_ENABLED: bool = false;
+
     /// Whether memory accesses should be alignment-checked.
     fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool;
 
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index ba579e25f03..847905e8343 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -45,3 +45,22 @@ pub(crate) fn create_static_alloc<'tcx>(
     assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
     interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
 }
+
+/// This struct is needed to enforce `#[must_use]` on [tracing::span::EnteredSpan]
+/// while wrapping them in an `Option`.
+#[must_use]
+pub enum MaybeEnteredSpan {
+    Some(tracing::span::EnteredSpan),
+    None,
+}
+
+#[macro_export]
+macro_rules! enter_trace_span {
+    ($machine:ident, $($tt:tt)*) => {
+        if $machine::TRACING_ENABLED {
+            $crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
+        } else {
+            $crate::interpret::tracing_utils::MaybeEnteredSpan::None
+        }
+    }
+}
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index d423d8acefd..f33f6b7cac1 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -4,7 +4,7 @@
 //! green/native threading. This is just a bare-bones enough solution for
 //! librustdoc, it is not production quality at all.
 
-cfg_match! {
+cfg_select! {
     target_os = "linux" => {
         mod linux;
         use linux as imp;
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 865424fd6bb..b34a7fdb9e4 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -19,7 +19,7 @@
 #![feature(ascii_char_variants)]
 #![feature(assert_matches)]
 #![feature(auto_traits)]
-#![feature(cfg_match)]
+#![feature(cfg_select)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(extend_one)]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 60f007083ba..36649a36070 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -860,7 +860,7 @@ fn get_thread_id() -> u32 {
 }
 
 // Memory reporting
-cfg_match! {
+cfg_select! {
     windows => {
         pub fn get_resident_set_size() -> Option<usize> {
             use windows::{
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index 33ac279f3e0..31abea93819 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -354,6 +354,20 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
             .collect()
     }
 
+    /// Given an element A, elements B with the lowest index such that `A R B`
+    /// and `B R A`, or `A` if no such element exists.
+    pub fn minimal_scc_representative(&self, a: T) -> T {
+        match self.index(a) {
+            Some(a_i) => self.with_closure(|closure| {
+                closure
+                    .iter(a_i.0)
+                    .find(|i| closure.contains(*i, a_i.0))
+                    .map_or(a, |i| self.elements[i])
+            }),
+            None => a,
+        }
+    }
+
     fn with_closure<OP, R>(&self, op: OP) -> R
     where
         OP: FnOnce(&BitMatrix<usize, usize>) -> R,
diff --git a/compiler/rustc_data_structures/src/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
index e756c546e41..cba14b5b64b 100644
--- a/compiler/rustc_data_structures/src/transitive_relation/tests.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation/tests.rs
@@ -376,3 +376,44 @@ fn parent() {
     let p = relation.postdom_parent(3);
     assert_eq!(p, Some(0));
 }
+
+#[test]
+fn minimal_scc_representative_1() {
+    //      +---------+
+    //      v         |
+    // a -> c -> d -> e
+    //           ^    ^
+    //           |    |
+    //           b ---+
+
+    // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }",
+    let mut relation = TransitiveRelationBuilder::default();
+    relation.add("a", "c");
+    relation.add("c", "d");
+    relation.add("d", "e");
+    relation.add("e", "c");
+    relation.add("b", "d");
+    relation.add("b", "e");
+    let relation = relation.freeze();
+
+    assert_eq!(relation.minimal_scc_representative("a"), "a");
+    assert_eq!(relation.minimal_scc_representative("b"), "b");
+    assert_eq!(relation.minimal_scc_representative("c"), "c");
+    assert_eq!(relation.minimal_scc_representative("d"), "c");
+    assert_eq!(relation.minimal_scc_representative("e"), "c");
+}
+
+#[test]
+fn minimal_scc_representative_2() {
+    // "digraph { a -> b; a -> a; b -> a; c -> c}",
+    let mut relation = TransitiveRelationBuilder::default();
+    relation.add("a", "b");
+    relation.add("b", "a");
+    relation.add("a", "a");
+    relation.add("c", "c");
+    let relation = relation.freeze();
+
+    assert_eq!(relation.minimal_scc_representative("a"), "a");
+    assert_eq!(relation.minimal_scc_representative("b"), "a");
+    assert_eq!(relation.minimal_scc_representative("c"), "c");
+}
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 0ba139ea5cc..e8fd2f54d76 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -12,6 +12,7 @@ doctest = false
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index f5eaf7d616b..55751aa4908 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -11,7 +11,7 @@ use rustc_ast::token::MetaVarKind;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
-use rustc_attr_parsing::{AttributeKind, Deprecation, Stability, find_attr};
+use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 93604a149f1..783f061ec6c 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -10,7 +10,7 @@ use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::{AttributeKind, find_attr};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_feature::Features;
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index fa1d1ec0a86..f63ab303689 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -85,7 +85,7 @@ impl From<Ident> for LifetimeSyntax {
     fn from(ident: Ident) -> Self {
         let name = ident.name;
 
-        if name == kw::Empty {
+        if name == sym::empty {
             unreachable!("A lifetime name should never be empty");
         } else if name == kw::UnderscoreLifetime {
             LifetimeSyntax::Anonymous
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index 58213c4f4e4..f2b82c679b9 100644
--- a/compiler/rustc_hir_analysis/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -13,7 +13,7 @@ itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index f7f2b78f052..a3a0e276f74 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
 
 hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
 
-hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters
+hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$what} of a trait with uninferred generic parameters
     .suggestion = use a fully qualified path with inferred lifetimes
 
 hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index da94331aa26..06814eaefe8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -2,8 +2,7 @@ use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
 use rustc_abi::FieldIdx;
-use rustc_attr_parsing::AttributeKind;
-use rustc_attr_parsing::ReprAttr::ReprPacked;
+use rustc_attr_data_structures::ReprAttr::ReprPacked;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
@@ -31,7 +30,7 @@ use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use tracing::{debug, instrument};
 use ty::TypingMode;
-use {rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_attr_data_structures as attrs, rustc_hir as hir};
 
 use super::compare_impl_item::check_type_bounds;
 use super::*;
@@ -1154,7 +1153,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
     let repr = def.repr();
     if repr.packed() {
         if let Some(reprs) =
-            attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r)
+            attrs::find_attr!(tcx.get_all_attrs(def.did()), attrs::AttributeKind::Repr(r) => r)
         {
             for (r, _) in reprs {
                 if let ReprPacked(pack) = r
@@ -1371,9 +1370,9 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     def.destructor(tcx); // force the destructor to be evaluated
 
     if def.variants().is_empty() {
-        attr::find_attr!(
+        attrs::find_attr!(
             tcx.get_all_attrs(def_id),
-            AttributeKind::Repr(rs) => {
+            attrs::AttributeKind::Repr(rs) => {
                 struct_span_code_err!(
                     tcx.dcx(),
                     rs.first().unwrap().1,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 4520fbe352c..f5206d9a015 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -44,7 +44,6 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument};
 
 use crate::errors;
-use crate::hir_ty_lowering::errors::assoc_tag_str;
 use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
 
 pub(crate) mod dump;
@@ -89,6 +88,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         opaque_ty_origin,
         rendered_precise_capturing_args,
         const_param_default,
+        anon_const_kind,
         ..*providers
     };
 }
@@ -444,13 +444,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
         self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
     }
 
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,
         item_segment: &rustc_hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
             let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@@ -525,7 +524,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
                 inferred_sugg,
                 bound,
                 mpart_sugg,
-                what: assoc_tag_str(assoc_tag),
+                what: self.tcx.def_descr(item_def_id),
             }))
         }
     }
@@ -1828,3 +1827,27 @@ fn const_param_default<'tcx>(
         .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
     ty::EarlyBinder::bind(ct)
 }
+
+fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
+    let hir_id = tcx.local_def_id_to_hir_id(def);
+    let const_arg_id = tcx.parent_hir_id(hir_id);
+    match tcx.hir_node(const_arg_id) {
+        hir::Node::ConstArg(_) => {
+            if tcx.features().generic_const_exprs() {
+                ty::AnonConstKind::GCE
+            } else if tcx.features().min_generic_const_args() {
+                ty::AnonConstKind::MCG
+            } else if let hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Repeat(_, repeat_count),
+                ..
+            }) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
+                && repeat_count.hir_id == const_arg_id
+            {
+                ty::AnonConstKind::RepeatExprCount
+            } else {
+                ty::AnonConstKind::MCG
+            }
+        }
+        _ => ty::AnonConstKind::NonTypeSystem,
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 2bed28d7b71..7eb896f0bf1 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 }
             }
 
-            if in_param_ty {
-                // We do not allow generic parameters in anon consts if we are inside
-                // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
-                None
-            } else if tcx.features().generic_const_exprs() {
-                let parent_node = tcx.parent_hir_node(hir_id);
-                debug!(?parent_node);
-                if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
-                    && constant.hir_id == hir_id
-                {
-                    // enum variant discriminants are not allowed to use any kind of generics
-                    None
-                } else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id)
+            match tcx.anon_const_kind(def_id) {
+                // Stable: anon consts are not able to use any generic parameters...
+                ty::AnonConstKind::MCG => None,
+                // we provide generics to repeat expr counts as a backwards compatibility hack. #76200
+                ty::AnonConstKind::RepeatExprCount => Some(parent_did),
+
+                // Even GCE anon const should not be allowed to use generic parameters as it would be
+                // trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
+                //
+                // We could potentially mirror the hack done for defaults of generic parameters but
+                // this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
+                // hack for defaulted parameters should be removed eventually anyway.
+                ty::AnonConstKind::GCE if in_param_ty => None,
+                // GCE anon consts as a default for a generic parameter should have their provided generics
+                // "truncated" up to whatever generic parameter this anon const is within the default of.
+                //
+                // FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
+                // parameter defaults, e.g. `T = Foo</*defid*/>`.
+                ty::AnonConstKind::GCE
+                    if let Some(param_id) =
+                        tcx.hir_opt_const_param_default_param_def_id(hir_id) =>
                 {
                     // If the def_id we are calling generics_of on is an anon ct default i.e:
                     //
@@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                         has_self: generics.has_self,
                         has_late_bound_regions: generics.has_late_bound_regions,
                     };
-                } else {
-                    // HACK(eddyb) this provides the correct generics when
-                    // `feature(generic_const_expressions)` is enabled, so that const expressions
-                    // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
-                    //
-                    // Note that we do not supply the parent generics when using
-                    // `min_const_generics`.
-                    Some(parent_did)
                 }
-            } else {
-                let parent_node = tcx.parent_hir_node(hir_id);
-                let parent_node = match parent_node {
-                    Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
-                    _ => parent_node,
-                };
-                match parent_node {
-                    // HACK(eddyb) this provides the correct generics for repeat
-                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
-                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
-                    // as they shouldn't be able to cause query cycle errors.
-                    Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
-                        if ct.anon_const_hir_id() == Some(hir_id) =>
-                    {
-                        Some(parent_did)
-                    }
-                    Node::TyPat(_) => Some(parent_did),
-                    // Field default values inherit the ADT's generics.
-                    Node::Field(_) => Some(parent_did),
-                    _ => None,
+                ty::AnonConstKind::GCE => Some(parent_did),
+
+                // Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
+                ty::AnonConstKind::NonTypeSystem
+                    if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
+                {
+                    Some(parent_did)
                 }
+                // Default to no generic parameters for other kinds of anon consts
+                ty::AnonConstKind::NonTypeSystem => None,
             }
         }
         Node::ConstBlock(_)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 4419d5dc7d6..bdc42c7a2d9 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -4,9 +4,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
+use rustc_hir::AmbigArg;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{AmbigArg, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
@@ -309,7 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     false => "`?Sized`",
                 };
                 // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
-                tcx.dcx().span_err(
+                self.dcx().span_err(
                     unbound.span,
                     format!(
                         "relaxing a default bound only does something for {}; \
@@ -675,7 +675,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 // Good error for `where Trait::method(..): Send`.
                 let Some(self_ty) = opt_self_ty else {
-                    let guar = self.error_missing_qpath_self_ty(
+                    let guar = self.report_missing_self_ty_for_resolved_path(
                         trait_def_id,
                         hir_ty.span,
                         item_segment,
@@ -713,120 +713,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     Err(guar) => Ty::new_error(tcx, guar),
                 }
             }
-            hir::QPath::TypeRelative(qself, item_segment)
-                if item_segment.args.is_some_and(|args| {
+            hir::QPath::TypeRelative(hir_self_ty, segment)
+                if segment.args.is_some_and(|args| {
                     matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
                 }) =>
             {
-                match self
-                    .resolve_type_relative_return_type_notation(
-                        qself,
-                        item_segment,
-                        hir_ty.hir_id,
-                        hir_ty.span,
-                    )
-                    .and_then(|(candidate, item_def_id)| {
-                        self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span)
-                    }) {
-                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
-                    Err(guar) => Ty::new_error(tcx, guar),
-                }
-            }
-            _ => self.lower_ty(hir_ty),
-        }
-    }
-
-    /// Perform type-dependent lookup for a *method* for return type notation.
-    /// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`.
-    fn resolve_type_relative_return_type_notation(
-        &self,
-        qself: &'tcx hir::Ty<'tcx>,
-        item_segment: &'tcx hir::PathSegment<'tcx>,
-        qpath_hir_id: HirId,
-        span: Span,
-    ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> {
-        let tcx = self.tcx();
-        let qself_ty = self.lower_ty(qself);
-        let assoc_ident = item_segment.ident;
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
-            path.res
-        } else {
-            Res::Err
-        };
-
-        let bound = match (qself_ty.kind(), qself_res) {
-            (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
-                // `Self` in an impl of a trait -- we have a concrete self type and a
-                // trait reference.
-                let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
-                    // A cycle error occurred, most likely.
-                    self.dcx().span_bug(span, "expected cycle error");
-                };
-
-                self.probe_single_bound_for_assoc_item(
-                    || {
-                        traits::supertraits(
-                            tcx,
-                            ty::Binder::dummy(trait_ref.instantiate_identity()),
-                        )
-                    },
-                    AssocItemQSelf::SelfTyAlias,
+                let self_ty = self.lower_ty(hir_self_ty);
+                let (item_def_id, bound) = match self.resolve_type_relative_path(
+                    self_ty,
+                    hir_self_ty,
                     ty::AssocTag::Fn,
-                    assoc_ident,
-                    span,
+                    segment,
+                    hir_ty.hir_id,
+                    hir_ty.span,
                     None,
-                )?
-            }
-            (
-                &ty::Param(_),
-                Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
-            ) => self.probe_single_ty_param_bound_for_assoc_item(
-                param_did.expect_local(),
-                qself.span,
-                ty::AssocTag::Fn,
-                assoc_ident,
-                span,
-            )?,
-            _ => {
-                if let Err(reported) = qself_ty.error_reported() {
-                    return Err(reported);
-                } else {
-                    // FIXME(return_type_notation): Provide some structured suggestion here.
-                    let err = struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0223,
-                        "ambiguous associated function"
+                ) {
+                    Ok(result) => result,
+                    Err(guar) => return Ty::new_error(tcx, guar),
+                };
+
+                // Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
+                // which may happen via a higher-ranked where clause or supertrait.
+                // This is the same restrictions as associated types; even though we could
+                // support it, it just makes things a lot more difficult to support in
+                // `resolve_bound_vars`, since we'd need to introduce those as elided
+                // bound vars on the where clause too.
+                if bound.has_bound_vars() {
+                    return Ty::new_error(
+                        tcx,
+                        self.dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
+                            span: hir_ty.span,
+                            inferred_sugg: Some(hir_ty.span.with_hi(segment.ident.span.lo())),
+                            bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder()),
+                            mpart_sugg: None,
+                            what: tcx.def_descr(item_def_id),
+                        }),
                     );
-                    return Err(err.emit());
                 }
-            }
-        };
 
-        // Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
-        // which may happen via a higher-ranked where clause or supertrait.
-        // This is the same restrictions as associated types; even though we could
-        // support it, it just makes things a lot more difficult to support in
-        // `resolve_bound_vars`, since we'd need to introduce those as elided
-        // bound vars on the where clause too.
-        if bound.has_bound_vars() {
-            return Err(self.tcx().dcx().emit_err(
-                errors::AssociatedItemTraitUninferredGenericParams {
-                    span,
-                    inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
-                    bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
-                    mpart_sugg: None,
-                    what: "function",
-                },
-            ));
+                match self.lower_return_type_notation_ty(bound, item_def_id, hir_ty.span) {
+                    Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
+                    Err(guar) => Ty::new_error(tcx, guar),
+                }
+            }
+            _ => self.lower_ty(hir_ty),
         }
-
-        let trait_def_id = bound.def_id();
-        let assoc_ty = self
-            .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
-            .expect("failed to find associated type");
-
-        Ok((bound, assoc_ty.def_id))
     }
 
     /// Do the common parts of lowering an RTN type. This involves extending the
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index d1ee5a5494c..ebeb3b58208 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -35,7 +35,7 @@ pub(crate) fn validate_cmse_abi<'tcx>(
                     _ => tcx.hir_span(hir_id),
                 };
                 struct_span_code_err!(
-                    tcx.dcx(),
+                    dcx,
                     span,
                     E0781,
                     "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index f6e5149bd2b..9e44b645aca 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -78,15 +78,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         // We  don't support empty trait objects.
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            let guar = self.report_trait_object_with_no_traits_error(
-                span,
-                user_written_bounds.iter().copied(),
-            );
+            let guar =
+                self.report_trait_object_with_no_traits(span, user_written_bounds.iter().copied());
             return Ty::new_error(tcx, guar);
         }
         // We don't support >1 principal
         if regular_traits.len() > 1 {
-            let guar = self.report_trait_object_addition_traits_error(&regular_traits);
+            let guar = self.report_trait_object_addition_traits(&regular_traits);
             return Ty::new_error(tcx, guar);
         }
         // Don't create a dyn trait if we have errors in the principal.
@@ -132,7 +130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     if references_self {
                         // With trait alias and type alias combined, type resolver
                         // may not be able to catch all illegal `Self` usages (issue 139082)
-                        let guar = tcx.dcx().emit_err(SelfInTypeAlias { span });
+                        let guar = self.dcx().emit_err(SelfInTypeAlias { span });
                         b.term = replace_dummy_self_with_error(tcx, b.term, guar);
                     }
                 }
@@ -360,7 +358,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
                         && hir_bound.span.contains(span)
                 });
-                self.complain_about_missing_type_params(
+                self.report_missing_type_params(
                     missing_type_params,
                     trait_ref.def_id,
                     span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 3759a224ff7..45fee0fa402 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -3,11 +3,12 @@ use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
+    Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, listify, pluralize,
+    struct_span_code_err,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, HirId};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -23,6 +24,7 @@ use rustc_trait_selection::traits::{
     FulfillmentError, dyn_compatibility_violations_for_assoc_item,
 };
 use smallvec::SmallVec;
+use tracing::debug;
 
 use crate::errors::{
     self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
@@ -34,7 +36,7 @@ use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
-    pub(crate) fn complain_about_missing_type_params(
+    pub(crate) fn report_missing_type_params(
         &self,
         missing_type_params: Vec<Symbol>,
         def_id: DefId,
@@ -56,7 +58,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
     /// an error and attempt to build a reasonable structured suggestion.
-    pub(crate) fn complain_about_internal_fn_trait(
+    pub(crate) fn report_internal_fn_trait(
         &self,
         span: Span,
         trait_def_id: DefId,
@@ -112,7 +114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    pub(super) fn complain_about_assoc_item_not_found<I>(
+    pub(super) fn report_unresolved_assoc_item<I>(
         &self,
         all_candidates: impl Fn() -> I,
         qself: AssocItemQSelf,
@@ -132,7 +134,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .filter_by_name_unhygienic(assoc_ident.name)
                 .find(|item| tcx.hygienic_eq(assoc_ident, item.ident(tcx), r.def_id()))
         }) {
-            return self.complain_about_assoc_kind_mismatch(
+            return self.report_assoc_kind_mismatch(
                 assoc_item,
                 assoc_tag,
                 assoc_ident,
@@ -331,7 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self.dcx().emit_err(err)
     }
 
-    fn complain_about_assoc_kind_mismatch(
+    fn report_assoc_kind_mismatch(
         &self,
         assoc_item: &ty::AssocItem,
         assoc_tag: ty::AssocTag,
@@ -396,12 +398,177 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         })
     }
 
-    pub(super) fn report_ambiguous_assoc(
+    pub(crate) fn report_missing_self_ty_for_resolved_path(
+        &self,
+        trait_def_id: DefId,
+        span: Span,
+        item_segment: &hir::PathSegment<'tcx>,
+        assoc_tag: ty::AssocTag,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let path_str = tcx.def_path_str(trait_def_id);
+
+        let def_id = self.item_def_id();
+        debug!(item_def_id = ?def_id);
+
+        // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
+        let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
+        debug!(?parent_def_id);
+
+        // If the trait in segment is the same as the trait defining the item,
+        // use the `<Self as ..>` syntax in the error.
+        let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
+        let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
+
+        let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+            vec!["Self".to_string()]
+        } else {
+            // Find all the types that have an `impl` for the trait.
+            tcx.all_impls(trait_def_id)
+                .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
+                .filter(|header| {
+                    // Consider only accessible traits
+                    tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
+                        && header.polarity != ty::ImplPolarity::Negative
+                })
+                .map(|header| header.trait_ref.instantiate_identity().self_ty())
+                // We don't care about blanket impls.
+                .filter(|self_ty| !self_ty.has_non_region_param())
+                .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+                .collect()
+        };
+        // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+        // references the trait. Relevant for the first case in
+        // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
+        self.report_ambiguous_assoc_item_path(
+            span,
+            &type_names,
+            &[path_str],
+            item_segment.ident,
+            assoc_tag,
+        )
+    }
+
+    pub(super) fn report_unresolved_type_relative_path(
+        &self,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &hir::Ty<'_>,
+        assoc_tag: ty::AssocTag,
+        ident: Ident,
+        qpath_hir_id: HirId,
+        span: Span,
+        variant_def_id: Option<DefId>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let kind_str = assoc_tag_str(assoc_tag);
+        if variant_def_id.is_some() {
+            // Variant in type position
+            let msg = format!("expected {kind_str}, found variant `{ident}`");
+            self.dcx().span_err(span, msg)
+        } else if self_ty.is_enum() {
+            let mut err = self.dcx().create_err(errors::NoVariantNamed {
+                span: ident.span,
+                ident,
+                ty: self_ty,
+            });
+
+            let adt_def = self_ty.ty_adt_def().expect("enum is not an ADT");
+            if let Some(variant_name) = find_best_match_for_name(
+                &adt_def.variants().iter().map(|variant| variant.name).collect::<Vec<Symbol>>(),
+                ident.name,
+                None,
+            ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == variant_name)
+            {
+                let mut suggestion = vec![(ident.span, variant_name.to_string())];
+                if let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(expr), .. })
+                | hir::Node::Expr(expr) = tcx.parent_hir_node(qpath_hir_id)
+                    && let hir::ExprKind::Struct(..) = expr.kind
+                {
+                    match variant.ctor {
+                        None => {
+                            // struct
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                if variant.fields.is_empty() {
+                                    format!("{variant_name} {{}}")
+                                } else {
+                                    format!(
+                                        "{variant_name} {{ {} }}",
+                                        variant
+                                            .fields
+                                            .iter()
+                                            .map(|f| format!("{}: /* value */", f.name))
+                                            .collect::<Vec<_>>()
+                                            .join(", ")
+                                    )
+                                },
+                            )];
+                        }
+                        Some((hir::def::CtorKind::Fn, def_id)) => {
+                            // tuple
+                            let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
+                            let inputs = fn_sig.inputs().skip_binder();
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                format!(
+                                    "{variant_name}({})",
+                                    inputs
+                                        .iter()
+                                        .map(|i| format!("/* {i} */"))
+                                        .collect::<Vec<_>>()
+                                        .join(", ")
+                                ),
+                            )];
+                        }
+                        Some((hir::def::CtorKind::Const, _)) => {
+                            // unit
+                            suggestion = vec![(
+                                ident.span.with_hi(expr.span.hi()),
+                                variant_name.to_string(),
+                            )];
+                        }
+                    }
+                }
+                err.multipart_suggestion_verbose(
+                    "there is a variant with a similar name",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
+            } else {
+                err.span_label(ident.span, format!("variant not found in `{self_ty}`"));
+            }
+
+            if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
+                err.span_label(sp, format!("variant `{ident}` not found here"));
+            }
+
+            err.emit()
+        } else if let Err(reported) = self_ty.error_reported() {
+            reported
+        } else {
+            match self.maybe_report_similar_assoc_fn(span, self_ty, hir_self_ty) {
+                Ok(()) => {}
+                Err(reported) => return reported,
+            }
+
+            let traits: Vec<_> = self.probe_traits_that_match_assoc_ty(self_ty, ident);
+
+            self.report_ambiguous_assoc_item_path(
+                span,
+                &[self_ty.to_string()],
+                &traits,
+                ident,
+                assoc_tag,
+            )
+        }
+    }
+
+    pub(super) fn report_ambiguous_assoc_item_path(
         &self,
         span: Span,
         types: &[String],
         traits: &[String],
-        name: Symbol,
+        ident: Ident,
         assoc_tag: ty::AssocTag,
     ) -> ErrorGuaranteed {
         let kind_str = assoc_tag_str(assoc_tag);
@@ -421,6 +588,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Applicability::MachineApplicable,
             );
         } else {
+            let sugg_sp = span.until(ident.span);
+
             let mut types = types.to_vec();
             types.sort();
             let mut traits = traits.to_vec();
@@ -428,76 +597,79 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             match (&types[..], &traits[..]) {
                 ([], []) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
                             "if there were a type named `Type` that implements a trait named \
-                             `Trait` with associated {kind_str} `{name}`, you could use the \
+                             `Trait` with associated {kind_str} `{ident}`, you could use the \
                              fully-qualified path",
                         ),
-                        format!("<Type as Trait>::{name}"),
+                        "<Type as Trait>::",
                         Applicability::HasPlaceholders,
                     );
                 }
                 ([], [trait_str]) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
                             "if there were a type named `Example` that implemented `{trait_str}`, \
                              you could use the fully-qualified path",
                         ),
-                        format!("<Example as {trait_str}>::{name}"),
+                        format!("<Example as {trait_str}>::"),
                         Applicability::HasPlaceholders,
                     );
                 }
                 ([], traits) => {
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         format!(
                             "if there were a type named `Example` that implemented one of the \
-                             traits with associated {kind_str} `{name}`, you could use the \
+                             traits with associated {kind_str} `{ident}`, you could use the \
                              fully-qualified path",
                         ),
-                        traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
+                        traits.iter().map(|trait_str| format!("<Example as {trait_str}>::")),
                         Applicability::HasPlaceholders,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
                 ([type_str], []) => {
                     err.span_suggestion_verbose(
-                        span,
+                        sugg_sp,
                         format!(
-                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
+                            "if there were a trait named `Example` with associated {kind_str} `{ident}` \
                              implemented for `{type_str}`, you could use the fully-qualified path",
                         ),
-                        format!("<{type_str} as Example>::{name}"),
+                        format!("<{type_str} as Example>::"),
                         Applicability::HasPlaceholders,
                     );
                 }
                 (types, []) => {
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         format!(
-                            "if there were a trait named `Example` with associated {kind_str} `{name}` \
+                            "if there were a trait named `Example` with associated {kind_str} `{ident}` \
                              implemented for one of the types, you could use the fully-qualified \
                              path",
                         ),
                         types
                             .into_iter()
-                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
+                            .map(|type_str| format!("<{type_str} as Example>::")),
                         Applicability::HasPlaceholders,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
                 (types, traits) => {
                     let mut suggestions = vec![];
                     for type_str in types {
                         for trait_str in traits {
-                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+                            suggestions.push(format!("<{type_str} as {trait_str}>::"));
                         }
                     }
-                    err.span_suggestions(
-                        span,
+                    err.span_suggestions_with_style(
+                        sugg_sp,
                         "use fully-qualified syntax",
                         suggestions,
                         Applicability::MachineApplicable,
+                        SuggestionStyle::ShowAlways,
                     );
                 }
             }
@@ -505,7 +677,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub(crate) fn complain_about_ambiguous_inherent_assoc(
+    pub(crate) fn report_ambiguous_inherent_assoc_item(
         &self,
         name: Ident,
         candidates: Vec<DefId>,
@@ -518,12 +690,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             "multiple applicable items in scope"
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
-        self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
+        self.note_ambiguous_inherent_assoc_item(&mut err, candidates, span);
         err.emit()
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
-    fn note_ambiguous_inherent_assoc_ty(
+    fn note_ambiguous_inherent_assoc_item(
         &self,
         err: &mut Diag<'_>,
         candidates: Vec<DefId>,
@@ -566,7 +738,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     // FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
-    pub(crate) fn complain_about_inherent_assoc_not_found(
+    pub(crate) fn report_unresolved_inherent_assoc_item(
         &self,
         name: Ident,
         self_ty: Ty<'tcx>,
@@ -1046,7 +1218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    pub fn report_prohibit_generics_error<'a>(
+    pub fn report_prohibited_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
         args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
@@ -1128,7 +1300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub fn report_trait_object_addition_traits_error(
+    pub fn report_trait_object_addition_traits(
         &self,
         regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
     ) -> ErrorGuaranteed {
@@ -1171,7 +1343,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         err.emit()
     }
 
-    pub fn report_trait_object_with_no_traits_error(
+    pub fn report_trait_object_with_no_traits(
         &self,
         span: Span,
         user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 483b61add33..1f4692b19f1 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -103,7 +103,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // In case there is an associated type with the same name
             // Add the suggestion to this error
             if let Some(mut sugg) =
-                tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
+                self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
                 && let Suggestions::Enabled(ref mut s1) = diag.suggestions
                 && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
             {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 5e79e932015..6b21bbbfcd8 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -38,22 +38,20 @@ use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::mir::interpret::LitToConstInput;
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
-    self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
-    TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
+    self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
+    TypeVisitableExt, TypingMode, Upcast, fold_regions,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_session::parse::feature_err;
-use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use tracing::{debug, instrument};
 
-use self::errors::assoc_tag_str;
 use crate::check::check_abi_fn_ptr;
-use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
+use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -150,7 +148,7 @@ pub trait HirTyLowerer<'tcx> {
         assoc_ident: Ident,
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
 
-    /// Lower an associated type/const (from a trait) to a projection.
+    /// Lower a path to an associated item (of a trait) to a projection.
     ///
     /// This method has to be defined by the concrete lowering context because
     /// dealing with higher-ranked trait references depends on its capabilities:
@@ -162,13 +160,12 @@ pub trait HirTyLowerer<'tcx> {
     ///
     /// The canonical example of this is associated type `T::P` where `T` is a type
     /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`.
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
 
     fn lower_fn_sig(
@@ -245,39 +242,46 @@ pub enum FeedConstTy<'a, 'tcx> {
 }
 
 #[derive(Debug, Clone, Copy)]
-enum LowerAssocMode {
-    Type { permit_variants: bool },
+enum LowerTypeRelativePathMode {
+    Type(PermitVariants),
     Const,
 }
 
-impl LowerAssocMode {
+impl LowerTypeRelativePathMode {
     fn assoc_tag(self) -> ty::AssocTag {
         match self {
-            LowerAssocMode::Type { .. } => ty::AssocTag::Type,
-            LowerAssocMode::Const => ty::AssocTag::Const,
+            Self::Type(_) => ty::AssocTag::Type,
+            Self::Const => ty::AssocTag::Const,
         }
     }
 
     fn def_kind(self) -> DefKind {
         match self {
-            LowerAssocMode::Type { .. } => DefKind::AssocTy,
-            LowerAssocMode::Const => DefKind::AssocConst,
+            Self::Type(_) => DefKind::AssocTy,
+            Self::Const => DefKind::AssocConst,
         }
     }
 
-    fn permit_variants(self) -> bool {
+    fn permit_variants(self) -> PermitVariants {
         match self {
-            LowerAssocMode::Type { permit_variants } => permit_variants,
+            Self::Type(permit_variants) => permit_variants,
             // FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
             // resolve to const ctors/fn items respectively.
-            LowerAssocMode::Const => false,
+            Self::Const => PermitVariants::No,
         }
     }
 }
 
+/// Whether to permit a path to resolve to an enum variant.
 #[derive(Debug, Clone, Copy)]
-enum LoweredAssoc<'tcx> {
-    Term(DefId, GenericArgsRef<'tcx>),
+pub enum PermitVariants {
+    Yes,
+    No,
+}
+
+#[derive(Debug, Clone, Copy)]
+enum TypeRelativePath<'tcx> {
+    AssocItem(DefId, GenericArgsRef<'tcx>),
     Variant { adt: Ty<'tcx>, variant_did: DefId },
 }
 
@@ -745,7 +749,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             trait_ref.path.segments.split_last().unwrap().1.iter(),
             GenericsArgsErrExtend::None,
         );
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
+        self.report_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         let (generic_args, arg_count) = self.lower_generic_args_of_path(
             trait_ref.path.span,
@@ -920,7 +924,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: &hir::PathSegment<'tcx>,
         is_impl: bool,
     ) -> ty::TraitRef<'tcx> {
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
+        self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
         let (generic_args, _) =
             self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
@@ -933,7 +937,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     fn probe_trait_that_defines_assoc_item(
         &self,
         trait_def_id: DefId,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
     ) -> bool {
         self.tcx()
@@ -976,7 +980,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         ty_param_def_id: LocalDefId,
         ty_param_span: Span,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
         span: Span,
     ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@@ -1011,7 +1015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         all_candidates: impl Fn() -> I,
         qself: AssocItemQSelf,
-        assoc_tag: AssocTag,
+        assoc_tag: ty::AssocTag,
         assoc_ident: Ident,
         span: Span,
         constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@@ -1026,15 +1030,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         });
 
         let Some(bound) = matching_candidates.next() else {
-            let reported = self.complain_about_assoc_item_not_found(
+            return Err(self.report_unresolved_assoc_item(
                 all_candidates,
                 qself,
                 assoc_tag,
                 assoc_ident,
                 span,
                 constraint,
-            );
-            return Err(reported);
+            ));
         };
         debug!(?bound);
 
@@ -1127,7 +1130,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok(bound)
     }
 
-    /// Lower a [type-relative] path referring to an associated type or to an enum variant.
+    /// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type.
     ///
     /// If the path refers to an enum variant and `permit_variants` holds,
     /// the returned type is simply the provided self type `qself_ty`.
@@ -1148,61 +1151,63 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// described in the previous paragraph and their modeling of projections would likely be
     /// very similar in nature.
     ///
-    /// [type-relative]: hir::QPath::TypeRelative
     /// [#22519]: https://github.com/rust-lang/rust/issues/22519
     /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
     //
     // NOTE: When this function starts resolving `Trait::AssocTy` successfully
     // it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
     #[instrument(level = "debug", skip_all, ret)]
-    pub fn lower_assoc_path_ty(
+    pub fn lower_type_relative_ty_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
-        permit_variants: bool,
+        permit_variants: PermitVariants,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
-        match self.lower_assoc_path_shared(
-            hir_ref_id,
+        match self.lower_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            segment,
+            qpath_hir_id,
             span,
-            qself_ty,
-            qself,
-            assoc_segment,
-            LowerAssocMode::Type { permit_variants },
+            LowerTypeRelativePathMode::Type(permit_variants),
         )? {
-            LoweredAssoc::Term(def_id, args) => {
+            TypeRelativePath::AssocItem(def_id, args) => {
                 let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
                 let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
                 Ok((ty, tcx.def_kind(def_id), def_id))
             }
-            LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)),
+            TypeRelativePath::Variant { adt, variant_did } => {
+                Ok((adt, DefKind::Variant, variant_did))
+            }
         }
     }
 
+    /// Lower a [type-relative][hir::QPath::TypeRelative] path to a (type-level) constant.
     #[instrument(level = "debug", skip_all, ret)]
-    fn lower_assoc_path_const(
+    fn lower_type_relative_const_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
     ) -> Result<Const<'tcx>, ErrorGuaranteed> {
         let tcx = self.tcx();
-        let (def_id, args) = match self.lower_assoc_path_shared(
-            hir_ref_id,
+        let (def_id, args) = match self.lower_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            segment,
+            qpath_hir_id,
             span,
-            qself_ty,
-            qself,
-            assoc_segment,
-            LowerAssocMode::Const,
+            LowerTypeRelativePathMode::Const,
         )? {
-            LoweredAssoc::Term(def_id, args) => {
+            TypeRelativePath::AssocItem(def_id, args) => {
                 if !tcx.associated_item(def_id).is_type_const_capable(tcx) {
-                    let mut err = tcx.dcx().struct_span_err(
+                    let mut err = self.dcx().struct_span_err(
                         span,
                         "use of trait associated const without `#[type_const]`",
                     );
@@ -1213,75 +1218,134 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             // FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
             // not just const ctors
-            LoweredAssoc::Variant { .. } => {
+            TypeRelativePath::Variant { .. } => {
                 span_bug!(span, "unexpected variant res for type associated const path")
             }
         };
         Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args)))
     }
 
+    /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path.
     #[instrument(level = "debug", skip_all, ret)]
-    fn lower_assoc_path_shared(
+    fn lower_type_relative_path(
         &self,
-        hir_ref_id: HirId,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
         span: Span,
-        qself_ty: Ty<'tcx>,
-        qself: &'tcx hir::Ty<'tcx>,
-        assoc_segment: &'tcx hir::PathSegment<'tcx>,
-        mode: LowerAssocMode,
-    ) -> Result<LoweredAssoc<'tcx>, ErrorGuaranteed> {
-        debug!(%qself_ty, ?assoc_segment.ident);
+        mode: LowerTypeRelativePathMode,
+    ) -> Result<TypeRelativePath<'tcx>, ErrorGuaranteed> {
+        debug!(%self_ty, ?segment.ident);
         let tcx = self.tcx();
 
-        let assoc_ident = assoc_segment.ident;
-
         // Check if we have an enum variant or an inherent associated type.
-        let mut variant_resolution = None;
-        if let Some(adt_def) = self.probe_adt(span, qself_ty) {
+        let mut variant_def_id = None;
+        if let Some(adt_def) = self.probe_adt(span, self_ty) {
             if adt_def.is_enum() {
                 let variant_def = adt_def
                     .variants()
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did()));
+                    .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
                 if let Some(variant_def) = variant_def {
-                    if mode.permit_variants() {
-                        tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
+                    if let PermitVariants::Yes = mode.permit_variants() {
+                        tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
                         let _ = self.prohibit_generic_args(
-                            slice::from_ref(assoc_segment).iter(),
-                            GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
+                            slice::from_ref(segment).iter(),
+                            GenericsArgsErrExtend::EnumVariant {
+                                qself: hir_self_ty,
+                                assoc_segment: segment,
+                                adt_def,
+                            },
                         );
-                        return Ok(LoweredAssoc::Variant {
-                            adt: qself_ty,
+                        return Ok(TypeRelativePath::Variant {
+                            adt: self_ty,
                             variant_did: variant_def.def_id,
                         });
                     } else {
-                        variant_resolution = Some(variant_def.def_id);
+                        variant_def_id = Some(variant_def.def_id);
                     }
                 }
             }
 
             // FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
-            if let Some((did, args)) = self.probe_inherent_assoc_shared(
-                assoc_segment,
+            if let Some((did, args)) = self.probe_inherent_assoc_item(
+                segment,
                 adt_def.did(),
-                qself_ty,
-                hir_ref_id,
+                self_ty,
+                qpath_hir_id,
                 span,
                 mode.assoc_tag(),
             )? {
-                return Ok(LoweredAssoc::Term(did, args));
+                return Ok(TypeRelativePath::AssocItem(did, args));
             }
         }
 
-        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
-            path.res
-        } else {
-            Res::Err
+        let (item_def_id, bound) = self.resolve_type_relative_path(
+            self_ty,
+            hir_self_ty,
+            mode.assoc_tag(),
+            segment,
+            qpath_hir_id,
+            span,
+            variant_def_id,
+        )?;
+
+        let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?;
+
+        if let Some(variant_def_id) = variant_def_id {
+            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| {
+                lint.primary_message("ambiguous associated item");
+                let mut could_refer_to = |kind: DefKind, def_id, also| {
+                    let note_msg = format!(
+                        "`{}` could{} refer to the {} defined here",
+                        segment.ident,
+                        also,
+                        tcx.def_kind_descr(kind, def_id)
+                    );
+                    lint.span_note(tcx.def_span(def_id), note_msg);
+                };
+
+                could_refer_to(DefKind::Variant, variant_def_id, "");
+                could_refer_to(mode.def_kind(), item_def_id, " also");
+
+                lint.span_suggestion(
+                    span,
+                    "use fully-qualified syntax",
+                    format!(
+                        "<{} as {}>::{}",
+                        self_ty,
+                        tcx.item_name(bound.def_id()),
+                        segment.ident
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            });
+        }
+
+        Ok(TypeRelativePath::AssocItem(item_def_id, args))
+    }
+
+    /// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path.
+    fn resolve_type_relative_path(
+        &self,
+        self_ty: Ty<'tcx>,
+        hir_self_ty: &'tcx hir::Ty<'tcx>,
+        assoc_tag: ty::AssocTag,
+        segment: &'tcx hir::PathSegment<'tcx>,
+        qpath_hir_id: HirId,
+        span: Span,
+        variant_def_id: Option<DefId>,
+    ) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> {
+        let tcx = self.tcx();
+
+        let self_ty_res = match hir_self_ty.kind {
+            hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
+            _ => Res::Err,
         };
 
-        // Find the type of the associated item, and the trait where the associated
-        // item is declared.
-        let bound = match (qself_ty.kind(), qself_res) {
+        // Find the type of the assoc item, and the trait where the associated item is declared.
+        let bound = match (self_ty.kind(), self_ty_res) {
             (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
@@ -1292,14 +1356,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
                 self.probe_single_bound_for_assoc_item(
                     || {
-                        traits::supertraits(
-                            tcx,
-                            ty::Binder::dummy(trait_ref.instantiate_identity()),
-                        )
+                        let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity());
+                        traits::supertraits(tcx, trait_ref)
                     },
                     AssocItemQSelf::SelfTyAlias,
-                    mode.assoc_tag(),
-                    assoc_ident,
+                    assoc_tag,
+                    segment.ident,
                     span,
                     None,
                 )?
@@ -1309,167 +1371,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
             ) => self.probe_single_ty_param_bound_for_assoc_item(
                 param_did.expect_local(),
-                qself.span,
-                mode.assoc_tag(),
-                assoc_ident,
+                hir_self_ty.span,
+                assoc_tag,
+                segment.ident,
                 span,
             )?,
             _ => {
-                let kind_str = assoc_tag_str(mode.assoc_tag());
-                let reported = if variant_resolution.is_some() {
-                    // Variant in type position
-                    let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
-                    self.dcx().span_err(span, msg)
-                } else if qself_ty.is_enum() {
-                    let mut err = self.dcx().create_err(NoVariantNamed {
-                        span: assoc_ident.span,
-                        ident: assoc_ident,
-                        ty: qself_ty,
-                    });
-
-                    let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
-                    if let Some(variant_name) = find_best_match_for_name(
-                        &adt_def
-                            .variants()
-                            .iter()
-                            .map(|variant| variant.name)
-                            .collect::<Vec<Symbol>>(),
-                        assoc_ident.name,
-                        None,
-                    ) && let Some(variant) =
-                        adt_def.variants().iter().find(|s| s.name == variant_name)
-                    {
-                        let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())];
-                        if let hir::Node::Stmt(&hir::Stmt {
-                            kind: hir::StmtKind::Semi(expr), ..
-                        })
-                        | hir::Node::Expr(expr) = tcx.parent_hir_node(hir_ref_id)
-                            && let hir::ExprKind::Struct(..) = expr.kind
-                        {
-                            match variant.ctor {
-                                None => {
-                                    // struct
-                                    suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
-                                        if variant.fields.is_empty() {
-                                            format!("{variant_name} {{}}")
-                                        } else {
-                                            format!(
-                                                "{variant_name} {{ {} }}",
-                                                variant
-                                                    .fields
-                                                    .iter()
-                                                    .map(|f| format!("{}: /* value */", f.name))
-                                                    .collect::<Vec<_>>()
-                                                    .join(", ")
-                                            )
-                                        },
-                                    )];
-                                }
-                                Some((hir::def::CtorKind::Fn, def_id)) => {
-                                    // tuple
-                                    let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
-                                    let inputs = fn_sig.inputs().skip_binder();
-                                    suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
-                                        format!(
-                                            "{variant_name}({})",
-                                            inputs
-                                                .iter()
-                                                .map(|i| format!("/* {i} */"))
-                                                .collect::<Vec<_>>()
-                                                .join(", ")
-                                        ),
-                                    )];
-                                }
-                                Some((hir::def::CtorKind::Const, _)) => {
-                                    // unit
-                                    suggestion = vec![(
-                                        assoc_ident.span.with_hi(expr.span.hi()),
-                                        variant_name.to_string(),
-                                    )];
-                                }
-                            }
-                        }
-                        err.multipart_suggestion_verbose(
-                            "there is a variant with a similar name",
-                            suggestion,
-                            Applicability::HasPlaceholders,
-                        );
-                    } else {
-                        err.span_label(
-                            assoc_ident.span,
-                            format!("variant not found in `{qself_ty}`"),
-                        );
-                    }
-
-                    if let Some(sp) = tcx.hir_span_if_local(adt_def.did()) {
-                        err.span_label(sp, format!("variant `{assoc_ident}` not found here"));
-                    }
-
-                    err.emit()
-                } else if let Err(reported) = qself_ty.error_reported() {
-                    reported
-                } else {
-                    self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
-
-                    let traits: Vec<_> =
-                        self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
-
-                    // Don't print `ty::Error` to the user.
-                    self.report_ambiguous_assoc(
-                        span,
-                        &[qself_ty.to_string()],
-                        &traits,
-                        assoc_ident.name,
-                        mode.assoc_tag(),
-                    )
-                };
-                return Err(reported);
+                return Err(self.report_unresolved_type_relative_path(
+                    self_ty,
+                    hir_self_ty,
+                    assoc_tag,
+                    segment.ident,
+                    qpath_hir_id,
+                    span,
+                    variant_def_id,
+                ));
             }
         };
 
-        let trait_did = bound.def_id();
         let assoc_item = self
-            .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
+            .probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id())
             .expect("failed to find associated item");
-        let (def_id, args) = self.lower_assoc_shared(
-            span,
-            assoc_item.def_id,
-            assoc_segment,
-            bound,
-            mode.assoc_tag(),
-        )?;
-        let result = LoweredAssoc::Term(def_id, args);
-
-        if let Some(variant_def_id) = variant_resolution {
-            tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
-                lint.primary_message("ambiguous associated item");
-                let mut could_refer_to = |kind: DefKind, def_id, also| {
-                    let note_msg = format!(
-                        "`{}` could{} refer to the {} defined here",
-                        assoc_ident,
-                        also,
-                        tcx.def_kind_descr(kind, def_id)
-                    );
-                    lint.span_note(tcx.def_span(def_id), note_msg);
-                };
 
-                could_refer_to(DefKind::Variant, variant_def_id, "");
-                could_refer_to(mode.def_kind(), assoc_item.def_id, " also");
-
-                lint.span_suggestion(
-                    span,
-                    "use fully-qualified syntax",
-                    format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
-                    Applicability::MachineApplicable,
-                );
-            });
-        }
-        Ok(result)
+        Ok((assoc_item.def_id, bound))
     }
 
-    fn probe_inherent_assoc_shared(
+    /// Search for inherent associated items for use at the type level.
+    fn probe_inherent_assoc_item(
         &self,
         segment: &hir::PathSegment<'tcx>,
         adt_did: DefId,
@@ -1624,7 +1552,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .collect();
 
         match &applicable_candidates[..] {
-            &[] => Err(self.complain_about_inherent_assoc_not_found(
+            &[] => Err(self.report_unresolved_inherent_assoc_item(
                 name,
                 self_ty,
                 candidates,
@@ -1635,7 +1563,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             &[applicable_candidate] => Ok(applicable_candidate),
 
-            &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc(
+            &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
                 name,
                 applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
                 span,
@@ -1763,9 +1691,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .collect()
     }
 
-    /// Lower a qualified path to a type.
+    /// Lower a [resolved][hir::QPath::Resolved] associated type path to a projection.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_ty(
+    fn lower_resolved_assoc_ty_path(
         &self,
         span: Span,
         opt_self_ty: Option<Ty<'tcx>>,
@@ -1773,7 +1701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: Option<&hir::PathSegment<'tcx>>,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Ty<'tcx> {
-        match self.lower_qpath_shared(
+        match self.lower_resolved_assoc_item_path(
             span,
             opt_self_ty,
             item_def_id,
@@ -1788,9 +1716,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    /// Lower a qualified path to a const.
+    /// Lower a [resolved][hir::QPath::Resolved] associated const path to a (type-level) constant.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_const(
+    fn lower_resolved_assoc_const_path(
         &self,
         span: Span,
         opt_self_ty: Option<Ty<'tcx>>,
@@ -1798,7 +1726,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_segment: Option<&hir::PathSegment<'tcx>>,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Const<'tcx> {
-        match self.lower_qpath_shared(
+        match self.lower_resolved_assoc_item_path(
             span,
             opt_self_ty,
             item_def_id,
@@ -1814,8 +1742,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
+    /// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path.
     #[instrument(level = "debug", skip_all)]
-    fn lower_qpath_shared(
+    fn lower_resolved_assoc_item_path(
         &self,
         span: Span,
         opt_self_ty: Option<Ty<'tcx>>,
@@ -1830,7 +1759,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         debug!(?trait_def_id);
 
         let Some(self_ty) = opt_self_ty else {
-            return Err(self.error_missing_qpath_self_ty(
+            return Err(self.report_missing_self_ty_for_resolved_path(
                 trait_def_id,
                 span,
                 item_segment,
@@ -1849,57 +1778,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         Ok((item_def_id, item_args))
     }
 
-    fn error_missing_qpath_self_ty(
-        &self,
-        trait_def_id: DefId,
-        span: Span,
-        item_segment: &hir::PathSegment<'tcx>,
-        assoc_tag: ty::AssocTag,
-    ) -> ErrorGuaranteed {
-        let tcx = self.tcx();
-        let path_str = tcx.def_path_str(trait_def_id);
-
-        let def_id = self.item_def_id();
-        debug!(item_def_id = ?def_id);
-
-        // FIXME: document why/how this is different from `tcx.local_parent(def_id)`
-        let parent_def_id = tcx.hir_get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
-        debug!(?parent_def_id);
-
-        // If the trait in segment is the same as the trait defining the item,
-        // use the `<Self as ..>` syntax in the error.
-        let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
-        let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
-
-        let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
-            vec!["Self".to_string()]
-        } else {
-            // Find all the types that have an `impl` for the trait.
-            tcx.all_impls(trait_def_id)
-                .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
-                .filter(|header| {
-                    // Consider only accessible traits
-                    tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
-                        && header.polarity != ty::ImplPolarity::Negative
-                })
-                .map(|header| header.trait_ref.instantiate_identity().self_ty())
-                // We don't care about blanket impls.
-                .filter(|self_ty| !self_ty.has_non_region_param())
-                .map(|self_ty| tcx.erase_regions(self_ty).to_string())
-                .collect()
-        };
-        // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
-        // references the trait. Relevant for the first case in
-        // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
-        self.report_ambiguous_assoc(
-            span,
-            &type_names,
-            &[path_str],
-            item_segment.ident.name,
-            assoc_tag,
-        )
-    }
-
     pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
@@ -1908,7 +1786,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
         let mut result = Ok(());
         if let Some(_) = args_visitors.clone().next() {
-            result = Err(self.report_prohibit_generics_error(
+            result = Err(self.report_prohibited_generic_args(
                 segments.clone(),
                 args_visitors,
                 err_extend,
@@ -2069,14 +1947,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         generic_segments
     }
 
-    /// Lower a type `Path` to a type.
+    /// Lower a [resolved][hir::QPath::Resolved] path to a type.
     #[instrument(level = "debug", skip_all)]
-    pub fn lower_path(
+    pub fn lower_resolved_ty_path(
         &self,
         opt_self_ty: Option<Ty<'tcx>>,
         path: &hir::Path<'tcx>,
         hir_id: HirId,
-        permit_variants: bool,
+        permit_variants: PermitVariants,
     ) -> Ty<'tcx> {
         debug!(?path.res, ?opt_self_ty, ?path.segments);
         let tcx = self.tcx();
@@ -2107,7 +1985,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
-            Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
+            Res::Def(kind @ DefKind::Variant, def_id)
+                if let PermitVariants::Yes = permit_variants =>
+            {
                 // Lower "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
@@ -2202,7 +2082,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else {
                     None
                 };
-                self.lower_qpath_ty(
+                self.lower_resolved_assoc_ty_path(
                     span,
                     opt_self_ty,
                     def_id,
@@ -2298,7 +2178,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Const).
+    /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const).
     #[instrument(skip(self), level = "debug")]
     pub fn lower_const_arg(
         &self,
@@ -2323,7 +2203,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             if tcx.features().generic_const_parameter_types()
                 && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions())
             {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants with lifetimes in their type are not yet supported",
                 );
@@ -2334,7 +2214,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // use this type to feed the `type_of` and query results must not contain inference
             // variables otherwise we will ICE.
             if anon_const_type.has_non_region_infer() {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants with inferred types are not yet supported",
                 );
@@ -2344,7 +2224,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // We error when the type contains unsubstituted generics since we do not currently
             // give the anon const any of the generics from the parent.
             if anon_const_type.has_non_region_param() {
-                let e = tcx.dcx().span_err(
+                let e = self.dcx().span_err(
                     const_arg.span(),
                     "anonymous constants referencing generics are not yet supported",
                 );
@@ -2363,13 +2243,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                self.lower_const_path_resolved(opt_self_ty, path, hir_id)
+                self.lower_resolved_const_path(opt_self_ty, path, hir_id)
             }
-            hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
-                debug!(?qself, ?segment);
-                let ty = self.lower_ty(qself);
-                self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment)
-                    .unwrap_or_else(|guar| Const::new_error(tcx, guar))
+            hir::ConstArgKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
+                debug!(?hir_self_ty, ?segment);
+                let self_ty = self.lower_ty(hir_self_ty);
+                self.lower_type_relative_const_path(
+                    self_ty,
+                    hir_self_ty,
+                    segment,
+                    hir_id,
+                    const_arg.span(),
+                )
+                .unwrap_or_else(|guar| Const::new_error(tcx, guar))
             }
             hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
                 ty::Const::new_error_with_message(
@@ -2383,7 +2269,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    fn lower_const_path_resolved(
+    /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant.
+    fn lower_resolved_const_path(
         &self,
         opt_self_ty: Option<Ty<'tcx>>,
         path: &hir::Path<'tcx>,
@@ -2420,7 +2307,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 } else {
                     None
                 };
-                self.lower_qpath_const(
+                self.lower_resolved_assoc_const_path(
                     span,
                     opt_self_ty,
                     did,
@@ -2630,7 +2517,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
-                self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
+                self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, PermitVariants::No)
             }
             &hir::TyKind::OpaqueDef(opaque_ty) => {
                 // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
@@ -2684,12 +2571,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
                 Ty::new_error(tcx, guar)
             }
-            hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
-                debug!(?qself, ?segment);
-                let ty = self.lower_ty(qself);
-                self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
-                    .map(|(ty, _, _)| ty)
-                    .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
+            hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
+                debug!(?hir_self_ty, ?segment);
+                let self_ty = self.lower_ty(hir_self_ty);
+                self.lower_type_relative_ty_path(
+                    self_ty,
+                    hir_self_ty,
+                    segment,
+                    hir_ty.hir_id,
+                    hir_ty.span,
+                    PermitVariants::No,
+                )
+                .map(|(ty, _, _)| ty)
+                .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index f00125c3e09..c963f0ddefd 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
 itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index fd899425f62..4f77594deca 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -37,7 +37,7 @@
 
 use std::ops::Deref;
 
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, struct_span_code_err};
 use rustc_hir as hir;
@@ -1190,9 +1190,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (ty::FnDef(..), ty::FnDef(..)) => {
                         // Don't reify if the function types have a LUB, i.e., they
                         // are the same function and their parameters have a LUB.
-                        match self
-                            .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
-                        {
+                        match self.commit_if_ok(|_| {
+                            // We need to eagerly handle nested obligations due to lazy norm.
+                            if self.next_trait_solver() {
+                                let ocx = ObligationCtxt::new(self);
+                                let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?;
+                                if ocx.select_where_possible().is_empty() {
+                                    Ok(InferOk {
+                                        value,
+                                        obligations: ocx.into_pending_obligations(),
+                                    })
+                                } else {
+                                    Err(TypeError::Mismatch)
+                                }
+                            } else {
+                                self.at(cause, self.param_env).lub(prev_ty, new_ty)
+                            }
+                        }) {
                             // We have a LUB of prev_ty and new_ty, just return it.
                             Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
                             Err(_) => {
@@ -1840,17 +1854,16 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err);
 
         let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
-
-        let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
-        let parent = fcx.tcx.hir_node(parent_id);
+        let parent = fcx.tcx.parent_hir_node(block_or_return_id);
         if let Some(expr) = expression
             && let hir::Node::Expr(&hir::Expr {
                 kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
                 ..
             }) = parent
-            && !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..))
         {
-            fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
+            let needs_block =
+                !matches!(fcx.tcx.hir_body(body).value.kind, hir::ExprKind::Block(..));
+            fcx.suggest_missing_semicolon(&mut err, expr, expected, needs_block, true);
         }
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
@@ -1858,7 +1871,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         if let Some(expr) = expression
             && due_to_block
         {
-            fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
+            fcx.suggest_missing_semicolon(&mut err, expr, expected, false, false);
             let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
                 &mut err,
                 expr,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index d1bc54ed73e..8182851a015 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -84,7 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.annotate_expected_due_to_let_ty(err, expr, error);
         self.annotate_loop_expected_due_to_inference(err, expr, error);
-        if self.annotate_mut_binding_to_immutable_binding(err, expr, error) {
+        if self.annotate_mut_binding_to_immutable_binding(err, expr, expr_ty, expected, error) {
             return;
         }
 
@@ -799,17 +799,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Detect the following case
     ///
     /// ```text
-    /// fn change_object(mut a: &Ty) {
+    /// fn change_object(mut b: &Ty) {
     ///     let a = Ty::new();
     ///     b = a;
     /// }
     /// ```
     ///
-    /// where the user likely meant to modify the value behind there reference, use `a` as an out
+    /// where the user likely meant to modify the value behind there reference, use `b` as an out
     /// parameter, instead of mutating the local binding. When encountering this we suggest:
     ///
     /// ```text
-    /// fn change_object(a: &'_ mut Ty) {
+    /// fn change_object(b: &'_ mut Ty) {
     ///     let a = Ty::new();
     ///     *b = a;
     /// }
@@ -818,13 +818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut Diag<'_>,
         expr: &hir::Expr<'_>,
+        expr_ty: Ty<'tcx>,
+        expected: Ty<'tcx>,
         error: Option<TypeError<'tcx>>,
     ) -> bool {
-        if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error
+        if let Some(TypeError::Sorts(ExpectedFound { .. })) = error
             && let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
 
             // The difference between the expected and found values is one level of borrowing.
-            && self.can_eq(self.param_env, *inner, found)
+            && self.can_eq(self.param_env, *inner, expr_ty)
 
             // We have an `ident = expr;` assignment.
             && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 2c28ffd1fe3..1d86f7d223c 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -532,14 +532,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Break(destination, ref expr_opt) => {
                 self.check_expr_break(destination, expr_opt.as_deref(), expr)
             }
-            ExprKind::Continue(destination) => {
-                if destination.target_id.is_ok() {
-                    tcx.types.never
-                } else {
-                    // There was an error; make type-check fail.
-                    Ty::new_misc_error(tcx)
-                }
-            }
+            ExprKind::Continue(destination) => self.check_expr_continue(destination, expr),
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
             ExprKind::Become(call) => self.check_expr_become(call, expr),
             ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id),
@@ -918,7 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self,
                         &cause,
                         |mut err| {
-                            self.suggest_missing_semicolon(&mut err, expr, e_ty, false);
+                            self.suggest_missing_semicolon(&mut err, expr, e_ty, false, false);
                             self.suggest_mismatched_types_on_tail(
                                 &mut err, expr, ty, e_ty, target_id,
                             );
@@ -989,6 +982,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn check_expr_continue(
+        &self,
+        destination: hir::Destination,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        if let Ok(target_id) = destination.target_id {
+            if let hir::Node::Expr(hir::Expr { kind: ExprKind::Loop(..), .. }) =
+                self.tcx.hir_node(target_id)
+            {
+                self.tcx.types.never
+            } else {
+                // Liveness linting assumes `continue`s all point to loops. We'll report an error
+                // in `check_mod_loops`, but make sure we don't run liveness (#113379, #121623).
+                let guar = self.dcx().span_delayed_bug(
+                    expr.span,
+                    "found `continue` not pointing to loop, but no error reported",
+                );
+                Ty::new_error(self.tcx, guar)
+            }
+        } else {
+            // There was an error; make type-check fail.
+            Ty::new_misc_error(self.tcx)
+        }
+    }
+
     fn check_expr_return(
         &self,
         expr_opt: Option<&'tcx hir::Expr<'tcx>>,
@@ -1882,62 +1900,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // We defer checking whether the element type is `Copy` as it is possible to have
         // an inference variable as a repeat count and it seems unlikely that `Copy` would
         // have inference side effects required for type checking to succeed.
-        if tcx.features().generic_arg_infer() {
-            self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
-        // If the length is 0, we don't create any elements, so we don't copy any.
-        // If the length is 1, we don't copy that one element, we move it. Only check
-        // for `Copy` if the length is larger, or unevaluated.
-        } else if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
-            self.enforce_repeat_element_needs_copy_bound(element, element_ty);
-        }
+        self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
 
         let ty = Ty::new_array_with_const_len(tcx, t, count);
         self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));
         ty
     }
 
-    /// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
-    pub(super) fn enforce_repeat_element_needs_copy_bound(
-        &self,
-        element: &hir::Expr<'_>,
-        element_ty: Ty<'tcx>,
-    ) {
-        let tcx = self.tcx;
-        // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
-        match &element.kind {
-            hir::ExprKind::ConstBlock(..) => return,
-            hir::ExprKind::Path(qpath) => {
-                let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
-                if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
-                {
-                    return;
-                }
-            }
-            _ => {}
-        }
-        // If someone calls a const fn or constructs a const value, they can extract that
-        // out into a separate constant (or a const block in the future), so we check that
-        // to tell them that in the diagnostic. Does not affect typeck.
-        let is_constable = match element.kind {
-            hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
-                ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
-                _ => traits::IsConstable::No,
-            },
-            hir::ExprKind::Path(qpath) => {
-                match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
-                    Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
-                    _ => traits::IsConstable::No,
-                }
-            }
-            _ => traits::IsConstable::No,
-        };
-
-        let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
-        let code =
-            traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span };
-        self.require_type_meets(element_ty, element.span, code, lang_item);
-    }
-
     fn check_expr_tuple(
         &self,
         elts: &'tcx [hir::Expr<'tcx>],
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index d2cdfe22a3a..786d7639a05 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -4,12 +4,12 @@ use itertools::Itertools;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize};
-use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, HirId, Node, QPath};
+use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath};
 use rustc_hir_analysis::check::potentially_plural_count;
-use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
+use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
 use rustc_index::IndexVec;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
 use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -104,24 +104,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_repeat_exprs(&self) {
         let mut deferred_repeat_expr_checks = self.deferred_repeat_expr_checks.borrow_mut();
         debug!("FnCtxt::check_repeat_exprs: {} deferred checks", deferred_repeat_expr_checks.len());
-        for (element, element_ty, count) in deferred_repeat_expr_checks.drain(..) {
-            // We want to emit an error if the const is not structurally resolveable as otherwise
-            // we can find up conservatively proving `Copy` which may infer the repeat expr count
-            // to something that never required `Copy` in the first place.
-            let count =
-                self.structurally_resolve_const(element.span, self.normalize(element.span, count));
-
-            // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count
-            // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1.
-            if count.references_error() {
-                continue;
-            }
 
-            // If the length is 0, we don't create any elements, so we don't copy any.
-            // If the length is 1, we don't copy that one element, we move it. Only check
-            // for `Copy` if the length is larger.
-            if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
-                self.enforce_repeat_element_needs_copy_bound(element, element_ty);
+        let deferred_repeat_expr_checks = deferred_repeat_expr_checks
+            .drain(..)
+            .flat_map(|(element, element_ty, count)| {
+                // Actual constants as the repeat element are inserted repeatedly instead
+                // of being copied via `Copy`, so we don't need to attempt to structurally
+                // resolve the repeat count which may unnecessarily error.
+                match &element.kind {
+                    hir::ExprKind::ConstBlock(..) => return None,
+                    hir::ExprKind::Path(qpath) => {
+                        let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
+                        if let Res::Def(DefKind::Const | DefKind::AssocConst, _) = res {
+                            return None;
+                        }
+                    }
+                    _ => {}
+                }
+
+                // We want to emit an error if the const is not structurally resolveable
+                // as otherwise we can wind up conservatively proving `Copy` which may
+                // infer the repeat expr count to something that never required `Copy` in
+                // the first place.
+                let count = self
+                    .structurally_resolve_const(element.span, self.normalize(element.span, count));
+
+                // Avoid run on "`NotCopy: Copy` is not implemented" errors when the
+                // repeat expr count is erroneous/unknown. The user might wind up
+                // specifying a repeat count of 0/1.
+                if count.references_error() {
+                    return None;
+                }
+
+                Some((element, element_ty, count))
+            })
+            // We collect to force the side effects of structurally resolving the repeat
+            // count to happen in one go, to avoid side effects from proving `Copy`
+            // affecting whether repeat counts are known or not. If we did not do this we
+            // would get results that depend on the order that we evaluate each repeat
+            // expr's `Copy` check.
+            .collect::<Vec<_>>();
+
+        let enforce_copy_bound = |element: &hir::Expr<'_>, element_ty| {
+            // If someone calls a const fn or constructs a const value, they can extract that
+            // out into a separate constant (or a const block in the future), so we check that
+            // to tell them that in the diagnostic. Does not affect typeck.
+            let is_constable = match element.kind {
+                hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
+                    ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => {
+                        traits::IsConstable::Fn
+                    }
+                    _ => traits::IsConstable::No,
+                },
+                hir::ExprKind::Path(qpath) => {
+                    match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
+                        Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
+                        _ => traits::IsConstable::No,
+                    }
+                }
+                _ => traits::IsConstable::No,
+            };
+
+            let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+            let code = traits::ObligationCauseCode::RepeatElementCopy {
+                is_constable,
+                elt_span: element.span,
+            };
+            self.require_type_meets(element_ty, element.span, code, lang_item);
+        };
+
+        for (element, element_ty, count) in deferred_repeat_expr_checks {
+            match count.kind() {
+                ty::ConstKind::Value(val) => {
+                    if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) {
+                        enforce_copy_bound(element, element_ty)
+                    } else {
+                        // If the length is 0 or 1 we don't actually copy the element, we either don't create it
+                        // or we just use the one value.
+                    }
+                }
+
+                // If the length is a generic parameter or some rigid alias then conservatively
+                // require `element_ty: Copy` as it may wind up being `>1` after monomorphization.
+                ty::ConstKind::Param(_)
+                | ty::ConstKind::Expr(_)
+                | ty::ConstKind::Placeholder(_)
+                | ty::ConstKind::Unevaluated(_) => enforce_copy_bound(element, element_ty),
+
+                ty::ConstKind::Bound(_, _) | ty::ConstKind::Infer(_) | ty::ConstKind::Error(_) => {
+                    unreachable!()
+                }
             }
         }
     }
@@ -2105,15 +2177,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *qpath {
             QPath::Resolved(ref maybe_qself, path) => {
                 let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
-                let ty = self.lowerer().lower_path(self_ty, path, hir_id, true);
+                let ty = self.lowerer().lower_resolved_ty_path(
+                    self_ty,
+                    path,
+                    hir_id,
+                    PermitVariants::Yes,
+                );
                 (path.res, LoweredTy::from_raw(self, path_span, ty))
             }
-            QPath::TypeRelative(qself, segment) => {
-                let ty = self.lower_ty(qself);
+            QPath::TypeRelative(hir_self_ty, segment) => {
+                let self_ty = self.lower_ty(hir_self_ty);
 
-                let result = self
-                    .lowerer()
-                    .lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true);
+                let result = self.lowerer().lower_type_relative_ty_path(
+                    self_ty.raw,
+                    hir_self_ty,
+                    segment,
+                    hir_id,
+                    path_span,
+                    PermitVariants::Yes,
+                );
                 let ty = result
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index de189b30109..ea0adf16b1a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -308,17 +308,16 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         ))
     }
 
-    fn lower_assoc_shared(
+    fn lower_assoc_item_path(
         &self,
         span: Span,
         item_def_id: DefId,
         item_segment: &rustc_hir::PathSegment<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-        _assoc_tag: ty::AssocTag,
     ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
         let trait_ref = self.instantiate_binder_with_fresh_vars(
             span,
-            // FIXME(mgca): this should be assoc const if that is the `kind`
+            // FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant.
             infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
             poly_trait_ref,
         );
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 1079262b5af..43b662ca453 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -764,6 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expression: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
         needs_block: bool,
+        parent_is_closure: bool,
     ) {
         if expected.is_unit() {
             // `BlockTailExpression` only relevant if the tail expr would be
@@ -799,6 +800,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
                 }
+                ExprKind::Path(..) | ExprKind::Lit(_)
+                    if parent_is_closure
+                        && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
+                {
+                    err.span_suggestion_verbose(
+                        expression.span.shrink_to_lo(),
+                        "consider ignoring the value",
+                        "_ = ",
+                        Applicability::MachineApplicable,
+                    );
+                }
                 _ => (),
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 956671fc66e..7d99b0e7869 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -218,7 +218,12 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
             );
         }
         let old_outermost_fn_param_pat = self.outermost_fn_param_pat.take();
-        intravisit::walk_pat(self, p);
+        if let PatKind::Guard(subpat, _) = p.kind {
+            // We'll visit the guard when checking it. Don't gather its locals twice.
+            self.visit_pat(subpat);
+        } else {
+            intravisit::walk_pat(self, p);
+        }
         self.outermost_fn_param_pat = old_outermost_fn_param_pat;
     }
 
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 161f5e981d4..5a814822163 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -2,6 +2,7 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(array_windows)]
+#![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
@@ -195,13 +196,16 @@ fn typeck_with_inspect<'tcx>(
         fcx.write_ty(id, expected_type);
     };
 
-    // Whether to check repeat exprs before/after inference fallback is somewhat arbitrary of a decision
-    // as neither option is strictly more permissive than the other. However, we opt to check repeat exprs
-    // first as errors from not having inferred array lengths yet seem less confusing than errors from inference
-    // fallback arbitrarily inferring something incompatible with `Copy` inference side effects.
+    // Whether to check repeat exprs before/after inference fallback is somewhat
+    // arbitrary of a decision as neither option is strictly more permissive than
+    // the other. However, we opt to check repeat exprs first as errors from not
+    // having inferred array lengths yet seem less confusing than errors from inference
+    // fallback arbitrarily inferring something incompatible with `Copy` inference
+    // side effects.
     //
-    // This should also be forwards compatible with moving repeat expr checks to a custom goal kind or using
-    // marker traits in the future.
+    // FIXME(#140855): This should also be forwards compatible with moving
+    // repeat expr checks to a custom goal kind or using marker traits in
+    // the future.
     fcx.check_repeat_exprs();
 
     fcx.type_inference_fallback();
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index a614b4f00ff..53b5dff9c6b 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -291,6 +291,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             probe::ObjectPick => {
                 let trait_def_id = pick.item.container_id(self.tcx);
 
+                // If the trait is not object safe (specifically, we care about when
+                // the receiver is not valid), then there's a chance that we will not
+                // actually be able to recover the object by derefing the receiver like
+                // we should if it were valid.
+                if !self.tcx.is_dyn_compatible(trait_def_id) {
+                    return ty::GenericArgs::extend_with_error(self.tcx, trait_def_id, &[]);
+                }
+
                 // This shouldn't happen for non-region error kinds, but may occur
                 // when we have error regions. Specifically, since we canonicalize
                 // during method steps, we may successfully deref when we assemble
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index bda051f1560..725240b480b 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1,7 +1,9 @@
+use std::assert_matches::debug_assert_matches;
 use std::cell::{Cell, RefCell};
 use std::cmp::max;
 use std::ops::Deref;
 
+use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_errors::Applicability;
@@ -15,7 +17,7 @@ use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::middle::stability;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::elaborate::supertrait_def_ids;
-use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
+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,
@@ -806,8 +808,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     );
                 }
             }
-            ty::Param(p) => {
-                self.assemble_inherent_candidates_from_param(p);
+            ty::Param(_) => {
+                self.assemble_inherent_candidates_from_param(raw_self_ty);
             }
             ty::Bool
             | ty::Char
@@ -908,18 +910,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
+    fn assemble_inherent_candidates_from_param(&mut self, param_ty: Ty<'tcx>) {
+        debug_assert_matches!(param_ty.kind(), ty::Param(_));
+
+        let tcx = self.tcx;
         let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
             let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
-                ty::ClauseKind::Trait(trait_predicate) => {
-                    match *trait_predicate.trait_ref.self_ty().kind() {
-                        ty::Param(p) if p == param_ty => {
-                            Some(bound_predicate.rebind(trait_predicate.trait_ref))
-                        }
-                        _ => None,
-                    }
-                }
+                ty::ClauseKind::Trait(trait_predicate) => DeepRejectCtxt::relate_rigid_rigid(tcx)
+                    .types_may_unify(param_ty, trait_predicate.trait_ref.self_ty())
+                    .then(|| bound_predicate.rebind(trait_predicate.trait_ref)),
                 ty::ClauseKind::RegionOutlives(_)
                 | ty::ClauseKind::TypeOutlives(_)
                 | ty::ClauseKind::Projection(_)
@@ -2333,10 +2333,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         };
         let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
         let attrs = self.fcx.tcx.hir_attrs(hir_id);
+
+        if is_doc_alias_attrs_contain_symbol(attrs.into_iter(), method.name) {
+            return true;
+        }
+
         for attr in attrs {
-            if attr.has_name(sym::doc) {
-                // do nothing
-            } else if attr.has_name(sym::rustc_confusables) {
+            if attr.has_name(sym::rustc_confusables) {
                 let Some(confusables) = attr.meta_item_list() else {
                     continue;
                 };
@@ -2348,33 +2351,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         return true;
                     }
                 }
-                continue;
-            } else {
-                continue;
-            };
-            let Some(values) = attr.meta_item_list() else {
-                continue;
-            };
-            for v in values {
-                if !v.has_name(sym::alias) {
-                    continue;
-                }
-                if let Some(nested) = v.meta_item_list() {
-                    // #[doc(alias("foo", "bar"))]
-                    for n in nested {
-                        if let Some(lit) = n.lit()
-                            && method.name == lit.symbol
-                        {
-                            return true;
-                        }
-                    }
-                } else if let Some(meta) = v.meta_item()
-                    && let Some(lit) = meta.name_value_literal()
-                    && method.name == lit.symbol
-                {
-                    // #[doc(alias = "foo")]
-                    return true;
-                }
             }
         }
         false
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 6a9fd7cdd48..342eed751a5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 
 use hir::Expr;
 use rustc_ast::ast::Mutability;
-use rustc_attr_parsing::{AttributeKind, find_attr};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 9be041f75d7..b2497cb0de1 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -9,17 +9,21 @@
 //! which creates a new `TypeckResults` which doesn't contain any inference variables.
 
 use std::mem;
+use std::ops::ControlFlow;
 
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::ExtendUnord;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{E0720, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, InferKind, Visitor};
 use rustc_hir::{self as hir, AmbigArg, HirId};
 use rustc_infer::traits::solve::Goal;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
 use rustc_middle::ty::{
-    self, DefiningScopeKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, fold_regions,
+    self, DefiningScopeKind, OpaqueHiddenType, Ty, TyCtxt, TypeFoldable, TypeFolder,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+    fold_regions,
 };
 use rustc_span::{Span, sym};
 use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
@@ -595,6 +599,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 entry.span = prev.span.substitute_dummy(hidden_type.span);
             }
         }
+
+        let recursive_opaques: Vec<_> = self
+            .typeck_results
+            .concrete_opaque_types
+            .iter()
+            .filter(|&(&def_id, hidden_ty)| {
+                hidden_ty
+                    .ty
+                    .visit_with(&mut HasRecursiveOpaque {
+                        def_id,
+                        seen: Default::default(),
+                        opaques: &self.typeck_results.concrete_opaque_types,
+                        tcx,
+                    })
+                    .is_break()
+            })
+            .map(|(def_id, hidden_ty)| (*def_id, hidden_ty.span))
+            .collect();
+        for (def_id, span) in recursive_opaques {
+            let guar = self
+                .fcx
+                .dcx()
+                .struct_span_err(span, "cannot resolve opaque type")
+                .with_code(E0720)
+                .emit();
+            self.typeck_results
+                .concrete_opaque_types
+                .insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) });
+        }
     }
 
     fn visit_field_id(&mut self, hir_id: HirId) {
@@ -959,3 +992,34 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerlyNormalizeConsts<'tcx> {
         self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct)
     }
 }
+
+struct HasRecursiveOpaque<'a, 'tcx> {
+    def_id: LocalDefId,
+    seen: FxHashSet<LocalDefId>,
+    opaques: &'a FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRecursiveOpaque<'_, 'tcx> {
+    type Result = ControlFlow<()>;
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        if let ty::Alias(ty::Opaque, alias_ty) = *t.kind()
+            && let Some(def_id) = alias_ty.def_id.as_local()
+        {
+            if self.def_id == def_id {
+                return ControlFlow::Break(());
+            }
+
+            if self.seen.insert(def_id)
+                && let Some(hidden_ty) = self.opaques.get(&def_id)
+            {
+                ty::EarlyBinder::bind(hidden_ty.ty)
+                    .instantiate(self.tcx, alias_ty.args)
+                    .visit_with(self)?;
+            }
+        }
+
+        t.super_visit_with(self)
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index a1a0926cd81..26ecaebe97f 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -17,8 +17,7 @@ use tracing::debug;
 
 use crate::infer::InferCtxt;
 use crate::infer::canonical::{
-    Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind,
-    OriginalQueryValues,
+    Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues,
 };
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -174,10 +173,8 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
         match r.kind() {
             ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r,
 
-            ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
-                CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
-                r,
-            ),
+            ty::RePlaceholder(placeholder) => canonicalizer
+                .canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r),
 
             ty::ReVar(vid) => {
                 let universe = infcx
@@ -186,10 +183,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                     .unwrap_region_constraints()
                     .probe_value(vid)
                     .unwrap_err();
-                canonicalizer.canonical_var_for_region(
-                    CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
-                    r,
-                )
+                canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r)
             }
 
             _ => {
@@ -294,7 +288,7 @@ struct Canonicalizer<'cx, 'tcx> {
     /// Set to `None` to disable the resolution of inference variables.
     infcx: Option<&'cx InferCtxt<'tcx>>,
     tcx: TyCtxt<'tcx>,
-    variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
+    variables: SmallVec<[CanonicalVarKind<'tcx>; 8]>,
     query_state: &'cx mut OriginalQueryValues<'tcx>,
     // Note that indices is only used once `var_values` is big enough to be
     // heap-allocated.
@@ -368,9 +362,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                             ui = ty::UniverseIndex::ROOT;
                         }
                         self.canonicalize_ty_var(
-                            CanonicalVarInfo {
-                                kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
-                            },
+                            CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
                             t,
                         )
                     }
@@ -382,10 +374,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 if nt != t {
                     return self.fold_ty(nt);
                 } else {
-                    self.canonicalize_ty_var(
-                        CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
-                        t,
-                    )
+                    self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t)
                 }
             }
             ty::Infer(ty::FloatVar(vid)) => {
@@ -393,10 +382,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 if nt != t {
                     return self.fold_ty(nt);
                 } else {
-                    self.canonicalize_ty_var(
-                        CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
-                        t,
-                    )
+                    self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t)
                 }
             }
 
@@ -408,10 +394,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 if !self.canonicalize_mode.preserve_universes() {
                     placeholder.universe = ty::UniverseIndex::ROOT;
                 }
-                self.canonicalize_ty_var(
-                    CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
-                    t,
-                )
+                self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
             }
 
             ty::Bound(debruijn, _) => {
@@ -483,10 +466,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                             // FIXME: perf problem described in #55921.
                             ui = ty::UniverseIndex::ROOT;
                         }
-                        return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
-                            ct,
-                        );
+                        return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct);
                     }
                 }
             }
@@ -501,10 +481,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 }
             }
             ty::ConstKind::Placeholder(placeholder) => {
-                return self.canonicalize_const_var(
-                    CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
-                    ct,
-                );
+                return self
+                    .canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct);
             }
             _ => {}
         }
@@ -595,7 +573,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
 
         let canonical_variables =
-            tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
+            tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_variables());
 
         let max_universe = canonical_variables
             .iter()
@@ -610,18 +588,22 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     /// or returns an existing variable if `kind` has already been
     /// seen. `kind` is expected to be an unbound variable (or
     /// potentially a free region).
-    fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>) -> BoundVar {
+    fn canonical_var(
+        &mut self,
+        var_kind: CanonicalVarKind<'tcx>,
+        value: GenericArg<'tcx>,
+    ) -> BoundVar {
         let Canonicalizer { variables, query_state, indices, .. } = self;
 
         let var_values = &mut query_state.var_values;
 
-        let universe = info.universe();
+        let universe = var_kind.universe();
         if universe != ty::UniverseIndex::ROOT {
             assert!(self.canonicalize_mode.preserve_universes());
 
             // Insert universe into the universe map. To preserve the order of the
             // universes in the value being canonicalized, we don't update the
-            // universe in `info` until we have finished canonicalizing.
+            // universe in `var_kind` until we have finished canonicalizing.
             match query_state.universe_map.binary_search(&universe) {
                 Err(idx) => query_state.universe_map.insert(idx, universe),
                 Ok(_) => {}
@@ -636,14 +618,14 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         if !var_values.spilled() {
             // `var_values` is stack-allocated. `indices` isn't used yet. Do a
             // direct linear search of `var_values`.
-            if let Some(idx) = var_values.iter().position(|&k| k == kind) {
+            if let Some(idx) = var_values.iter().position(|&v| v == value) {
                 // `kind` is already present in `var_values`.
                 BoundVar::new(idx)
             } else {
                 // `kind` isn't present in `var_values`. Append it. Likewise
-                // for `info` and `variables`.
-                variables.push(info);
-                var_values.push(kind);
+                // for `var_kind` and `variables`.
+                variables.push(var_kind);
+                var_values.push(value);
                 assert_eq!(variables.len(), var_values.len());
 
                 // If `var_values` has become big enough to be heap-allocated,
@@ -653,7 +635,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
                     *indices = var_values
                         .iter()
                         .enumerate()
-                        .map(|(i, &kind)| (kind, BoundVar::new(i)))
+                        .map(|(i, &value)| (value, BoundVar::new(i)))
                         .collect();
                 }
                 // The cv is the index of the appended element.
@@ -661,9 +643,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             }
         } else {
             // `var_values` is large. Do a hashmap search via `indices`.
-            *indices.entry(kind).or_insert_with(|| {
-                variables.push(info);
-                var_values.push(kind);
+            *indices.entry(value).or_insert_with(|| {
+                variables.push(var_kind);
+                var_values.push(value);
                 assert_eq!(variables.len(), var_values.len());
                 BoundVar::new(variables.len() - 1)
             })
@@ -673,7 +655,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     /// Replaces the universe indexes used in `var_values` with their index in
     /// `query_state.universe_map`. This minimizes the maximum universe used in
     /// the canonicalized value.
-    fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
+    fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> {
         if self.query_state.universe_map.len() == 1 {
             return self.variables;
         }
@@ -688,37 +670,33 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
 
         self.variables
             .iter()
-            .map(|v| CanonicalVarInfo {
-                kind: match v.kind {
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
-                        return *v;
-                    }
-                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
-                        CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
-                    }
-                    CanonicalVarKind::Region(u) => {
-                        CanonicalVarKind::Region(reverse_universe_map[&u])
-                    }
-                    CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
-                    CanonicalVarKind::PlaceholderTy(placeholder) => {
-                        CanonicalVarKind::PlaceholderTy(ty::Placeholder {
-                            universe: reverse_universe_map[&placeholder.universe],
-                            ..placeholder
-                        })
-                    }
-                    CanonicalVarKind::PlaceholderRegion(placeholder) => {
-                        CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
-                            universe: reverse_universe_map[&placeholder.universe],
-                            ..placeholder
-                        })
-                    }
-                    CanonicalVarKind::PlaceholderConst(placeholder) => {
-                        CanonicalVarKind::PlaceholderConst(ty::Placeholder {
-                            universe: reverse_universe_map[&placeholder.universe],
-                            ..placeholder
-                        })
-                    }
-                },
+            .map(|&kind| match kind {
+                CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                    return kind;
+                }
+                CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+                }
+                CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
+                CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
+                CanonicalVarKind::PlaceholderTy(placeholder) => {
+                    CanonicalVarKind::PlaceholderTy(ty::Placeholder {
+                        universe: reverse_universe_map[&placeholder.universe],
+                        ..placeholder
+                    })
+                }
+                CanonicalVarKind::PlaceholderRegion(placeholder) => {
+                    CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
+                        universe: reverse_universe_map[&placeholder.universe],
+                        ..placeholder
+                    })
+                }
+                CanonicalVarKind::PlaceholderConst(placeholder) => {
+                    CanonicalVarKind::PlaceholderConst(ty::Placeholder {
+                        universe: reverse_universe_map[&placeholder.universe],
+                        ..placeholder
+                    })
+                }
             })
             .collect()
     }
@@ -740,20 +718,17 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         &mut self,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        self.canonical_var_for_region(
-            CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) },
-            r,
-        )
+        self.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r)
     }
 
     /// Creates a canonical variable (with the given `info`)
     /// representing the region `r`; return a region referencing it.
     fn canonical_var_for_region(
         &mut self,
-        info: CanonicalVarInfo<'tcx>,
+        var_kind: CanonicalVarKind<'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        let var = self.canonical_var(info, r.into());
+        let var = self.canonical_var(var_kind, r.into());
         let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon };
         ty::Region::new_bound(self.cx(), self.binder_index, br)
     }
@@ -762,9 +737,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     /// if `ty_var` is bound to anything; if so, canonicalize
     /// *that*. Otherwise, create a new canonical variable for
     /// `ty_var`.
-    fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
+    fn canonicalize_ty_var(
+        &mut self,
+        var_kind: CanonicalVarKind<'tcx>,
+        ty_var: Ty<'tcx>,
+    ) -> Ty<'tcx> {
         debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
-        let var = self.canonical_var(info, ty_var.into());
+        let var = self.canonical_var(var_kind, ty_var.into());
         Ty::new_bound(self.tcx, self.binder_index, var.into())
     }
 
@@ -774,13 +753,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     /// `const_var`.
     fn canonicalize_const_var(
         &mut self,
-        info: CanonicalVarInfo<'tcx>,
-        const_var: ty::Const<'tcx>,
+        var_kind: CanonicalVarKind<'tcx>,
+        ct_var: ty::Const<'tcx>,
     ) -> ty::Const<'tcx> {
         debug_assert!(
-            !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var))
+            !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
         );
-        let var = self.canonical_var(info, const_var.into());
+        let var = self.canonical_var(var_kind, ct_var.into());
         ty::Const::new_bound(self.tcx, self.binder_index, var)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 3be07dbe208..5dffedc7099 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -81,14 +81,14 @@ impl<'tcx> InferCtxt<'tcx> {
     fn instantiate_canonical_vars(
         &self,
         span: Span,
-        variables: &List<CanonicalVarInfo<'tcx>>,
+        variables: &List<CanonicalVarKind<'tcx>>,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> CanonicalVarValues<'tcx> {
         CanonicalVarValues {
             var_values: self.tcx.mk_args_from_iter(
                 variables
                     .iter()
-                    .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
+                    .map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)),
             ),
         }
     }
@@ -104,10 +104,10 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn instantiate_canonical_var(
         &self,
         span: Span,
-        cv_info: CanonicalVarInfo<'tcx>,
+        kind: CanonicalVarKind<'tcx>,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> GenericArg<'tcx> {
-        match cv_info.kind {
+        match kind {
             CanonicalVarKind::Ty(ty_kind) => {
                 let ty = match ty_kind {
                     CanonicalTyVarKind::General(ui) => {
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 1ae864c454f..ec72e05494b 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -445,17 +445,17 @@ impl<'tcx> InferCtxt<'tcx> {
         // a fresh inference variable.
         let result_args = CanonicalVarValues {
             var_values: self.tcx.mk_args_from_iter(
-                query_response.variables.iter().enumerate().map(|(index, info)| {
-                    if info.universe() != ty::UniverseIndex::ROOT {
+                query_response.variables.iter().enumerate().map(|(index, var_kind)| {
+                    if var_kind.universe() != ty::UniverseIndex::ROOT {
                         // A variable from inside a binder of the query. While ideally these shouldn't
                         // exist at all, we have to deal with them for now.
-                        self.instantiate_canonical_var(cause.span, info, |u| {
+                        self.instantiate_canonical_var(cause.span, var_kind, |u| {
                             universe_map[u.as_usize()]
                         })
-                    } else if info.is_existential() {
+                    } else if var_kind.is_existential() {
                         match opt_values[BoundVar::new(index)] {
                             Some(k) => k,
-                            None => self.instantiate_canonical_var(cause.span, info, |u| {
+                            None => self.instantiate_canonical_var(cause.span, var_kind, |u| {
                                 universe_map[u.as_usize()]
                             }),
                         }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index e28639576f0..75d92ae7a2e 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -45,7 +45,7 @@ use crate::interface::Compiler;
 use crate::{errors, limits, proc_macro_decls, util};
 
 pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
-    let krate = sess
+    let mut krate = sess
         .time("parse_crate", || {
             let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
                 Input::File(file) => new_parser_from_file(&sess.psess, file, None),
@@ -64,6 +64,12 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
         input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1");
     }
 
+    rustc_builtin_macros::cmdline_attrs::inject(
+        &mut krate,
+        &sess.psess,
+        &sess.opts.unstable_opts.crate_attr,
+    );
+
     krate
 }
 
@@ -282,6 +288,7 @@ fn configure_and_expand(
     resolver.resolve_crate(&krate);
 
     CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
+    CStore::from_tcx(tcx).report_incompatible_async_drop_feature(tcx, &krate);
     krate
 }
 
@@ -804,17 +811,11 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
 
 pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
     compiler: &Compiler,
-    mut krate: rustc_ast::Crate,
+    krate: rustc_ast::Crate,
     f: F,
 ) -> T {
     let sess = &compiler.sess;
 
-    rustc_builtin_macros::cmdline_attrs::inject(
-        &mut krate,
-        &sess.psess,
-        &sess.opts.unstable_opts.crate_attr,
-    );
-
     let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
 
     let crate_name = get_crate_name(sess, &pre_configured_attrs);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 068d96c860f..20e081d3360 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -776,7 +776,8 @@ fn test_unstable_options_tracking_hash() {
         CoverageOptions {
             level: CoverageLevel::Mcdc,
             no_mir_spans: true,
-            discard_all_spans_in_codegen: true
+            discard_all_spans_in_codegen: true,
+            inject_unused_local_file: true,
         }
     );
     tracked!(crate_attr, vec!["abc".to_string()]);
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 7718f16984d..64751eaf1fe 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 08180bf8f8b..7fdf26bf3af 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -835,6 +835,7 @@ lint_unexpected_cfg_name_similar_name = there is a config with a similar name
 lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
 lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
 lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
+lint_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")`
 lint_unexpected_cfg_name_with_similar_value = found config with similar value
 
 lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
index 946dbc34f71..e2f5dd315d5 100644
--- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs
@@ -140,6 +140,14 @@ pub(super) fn unexpected_cfg_name(
 
     let code_sugg = if is_feature_cfg && is_from_cargo {
         lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
+    // Suggest correct `version("..")` predicate syntax
+    } else if let Some((_value, value_span)) = value
+        && name == sym::version
+    {
+        lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
+            between_name_and_value: name_span.between(value_span),
+            after_value: value_span.shrink_to_hi(),
+        }
     // Suggest the most probable if we found one
     } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
         is_feature_cfg |= best_match == sym::feature;
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7268a7f704f..af8fa8ffa1f 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2273,6 +2273,16 @@ pub(crate) mod unexpected_cfg_name {
     pub(crate) enum CodeSuggestion {
         #[help(lint_unexpected_cfg_define_features)]
         DefineFeatures,
+        #[multipart_suggestion(
+            lint_unexpected_cfg_name_version_syntax,
+            applicability = "machine-applicable"
+        )]
+        VersionSyntax {
+            #[suggestion_part(code = "(")]
+            between_name_and_value: Span,
+            #[suggestion_part(code = ")")]
+            after_value: Span,
+        },
         #[suggestion(
             lint_unexpected_cfg_name_similar_name_value,
             applicability = "maybe-incorrect",
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index d1138e8f1fa..048d377b78f 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,5 +1,6 @@
 use rustc_abi::ExternAbi;
-use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr};
+use rustc_attr_data_structures::{AttributeKind, ReprAttr};
+use rustc_attr_parsing::AttributeParser;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index 7cb00262b6f..d44f45177bd 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -5,7 +5,7 @@ use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::{bug, ty};
 use rustc_span::Span;
-use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir};
 
 use crate::LateContext;
 use crate::context::LintContext;
@@ -131,18 +131,18 @@ fn report_bin_hex_error(
     cx: &LateContext<'_>,
     hir_id: HirId,
     span: Span,
-    ty: attr::IntType,
+    ty: attrs::IntType,
     size: Size,
     repr_str: String,
     val: u128,
     negative: bool,
 ) {
     let (t, actually) = match ty {
-        attr::IntType::SignedInt(t) => {
+        attrs::IntType::SignedInt(t) => {
             let actually = if negative { -(size.sign_extend(val)) } else { size.sign_extend(val) };
             (t.name_str(), actually.to_string())
         }
-        attr::IntType::UnsignedInt(t) => {
+        attrs::IntType::UnsignedInt(t) => {
             let actually = size.truncate(val);
             (t.name_str(), actually.to_string())
         }
@@ -264,7 +264,7 @@ fn lint_int_literal<'tcx>(
                 cx,
                 hir_id,
                 span,
-                attr::IntType::SignedInt(ty::ast_int_ty(t)),
+                attrs::IntType::SignedInt(ty::ast_int_ty(t)),
                 Integer::from_int_ty(cx, t).size(),
                 repr_str,
                 v,
@@ -336,7 +336,7 @@ fn lint_uint_literal<'tcx>(
                 cx,
                 hir_id,
                 span,
-                attr::IntType::UnsignedInt(ty::ast_uint_ty(t)),
+                attrs::IntType::UnsignedInt(ty::ast_uint_ty(t)),
                 Integer::from_uint_ty(cx, t).size(),
                 repr_str,
                 lit_val,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 3cea24634fe..b8d242bad86 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -16,6 +16,7 @@ declare_lint_pass! {
     /// that are used by other parts of the compiler.
     HardwiredLints => [
         // tidy-alphabetical-start
+        AARCH64_SOFTFLOAT_NEON,
         ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
         AMBIGUOUS_ASSOCIATED_ITEMS,
         AMBIGUOUS_GLOB_IMPORTS,
@@ -5043,14 +5044,14 @@ declare_lint! {
     ///
     /// ```text
     /// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType`
-    /// --> $DIR/wasm_c_abi_transition.rs:17:1
-    ///  |
-    ///  | pub extern "C" fn my_fun(_x: MyType) {}
-    ///  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    ///  |
-    ///  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-    ///  = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762>
-    ///  = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
+    ///   --> $DIR/wasm_c_abi_transition.rs:17:1
+    ///    |
+    ///    | pub extern "C" fn my_fun(_x: MyType) {}
+    ///    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///    |
+    ///    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///    = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762>
+    ///    = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
     /// ```
     ///
     /// ### Explanation
@@ -5067,3 +5068,44 @@ declare_lint! {
         reference: "issue #138762 <https://github.com/rust-lang/rust/issues/138762>",
     };
 }
+
+declare_lint! {
+    /// The `aarch64_softfloat_neon` lint detects usage of `#[target_feature(enable = "neon")]` on
+    /// softfloat aarch64 targets. Enabling this target feature causes LLVM to alter the ABI of
+    /// function calls, making this attribute unsound to use.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs aarch64-unknown-none-softfloat)
+    /// #[target_feature(enable = "neon")]
+    /// fn with_neon() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: enabling the `neon` target feature on the current target is unsound due to ABI issues
+    ///   --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
+    ///    |
+    ///    | #[target_feature(enable = "neon")]
+    ///    |                  ^^^^^^^^^^^^^^^
+    ///    |
+    ///    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///    = note: for more information, see issue #134375 <https://github.com/rust-lang/rust/issues/134375>
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// If a function like `with_neon` above ends up containing calls to LLVM builtins, those will
+    /// not use the correct ABI. This is caused by a lack of support in LLVM for mixing code with
+    /// and without the `neon` target feature. The target feature should never have been stabilized
+    /// on this target due to this issue, but the problem was not known at the time of
+    /// stabilization.
+    pub AARCH64_SOFTFLOAT_NEON,
+    Warn,
+    "detects code that could be affected by ABI issues on aarch64 softfloat targets",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #134375 <https://github.com/rust-lang/rust/issues/134375>",
+    };
+}
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index ee377277017..2196f71299a 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -51,6 +51,7 @@ impl Parse for Query {
         let key = Pat::parse_single(&arg_content)?;
         arg_content.parse::<Token![:]>()?;
         let arg = arg_content.parse()?;
+        let _ = arg_content.parse::<Option<Token![,]>>()?;
         let result = input.parse()?;
 
         // Parse the query modifiers
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 26878c488b7..cfe412e99d8 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -10,6 +10,7 @@ libloading = "0.8.0"
 odht = { version = "0.3.1", features = ["nightly"] }
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index d997ba198ac..bccffe39243 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -1,6 +1,10 @@
 metadata_as_needed_compatibility =
     linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
 
+metadata_async_drop_types_in_dependency =
+    found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}`
+    .help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used
+
 metadata_bad_panic_strategy =
     the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 07fb2de8a3e..c7e9a2936f5 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -473,6 +473,27 @@ impl CStore {
         }
     }
 
+    // Report about async drop types in dependency if async drop feature is disabled
+    pub fn report_incompatible_async_drop_feature(&self, tcx: TyCtxt<'_>, krate: &Crate) {
+        if tcx.features().async_drop() {
+            return;
+        }
+        for (_cnum, data) in self.iter_crate_data() {
+            if data.is_proc_macro_crate() {
+                continue;
+            }
+            if data.has_async_drops() {
+                let extern_crate = data.name();
+                let local_crate = tcx.crate_name(LOCAL_CRATE);
+                tcx.dcx().emit_warn(errors::AsyncDropTypesInDependency {
+                    span: krate.spans.inner_span.shrink_to_lo(),
+                    extern_crate,
+                    local_crate,
+                });
+            }
+        }
+    }
+
     pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
         CStore {
             metadata_loader,
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index c45daeda85d..16f59793e63 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -811,3 +811,13 @@ pub struct UnknownTargetModifierUnsafeAllowed {
     pub span: Span,
     pub flag_name: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(metadata_async_drop_types_in_dependency)]
+#[help]
+pub struct AsyncDropTypesInDependency {
+    #[primary_span]
+    pub span: Span,
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index bd813cadedc..2e4352ca532 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1984,6 +1984,10 @@ impl CrateMetadata {
         self.root.header.hash
     }
 
+    pub(crate) fn has_async_drops(&self) -> bool {
+        self.root.tables.adt_async_destructor.len > 0
+    }
+
     fn num_def_ids(&self) -> usize {
         self.root.tables.def_keys.size()
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 76bae39ef8c..f40a2374bea 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -2,7 +2,7 @@ use std::any::Any;
 use std::mem;
 use std::sync::Arc;
 
-use rustc_attr_parsing::Deprecation;
+use rustc_attr_data_structures::Deprecation;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -425,6 +425,7 @@ provide! { tcx, def_id, other, cdata,
     doc_link_traits_in_scope => {
         tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
     }
+    anon_const_kind => { table }
 }
 
 pub(in crate::rmeta) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 7ac72ef814a..3ab989d2d3b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1569,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         <- tcx.explicit_implied_const_bounds(def_id).skip_binder());
                 }
             }
+            if let DefKind::AnonConst = def_kind {
+                record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
+            }
             if tcx.impl_method_has_trait_impl_trait_tys(def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
             {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index c86cf567283..077835283e9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -40,7 +40,7 @@ use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol};
 use rustc_target::spec::{PanicStrategy, TargetTuple};
 use table::TableBuilder;
-use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir};
 
 use crate::creader::CrateMetadataRef;
 
@@ -200,7 +200,7 @@ type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>;
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct ProcMacroData {
     proc_macro_decls_static: DefIndex,
-    stability: Option<attr::Stability>,
+    stability: Option<attrs::Stability>,
     macros: LazyArray<DefIndex>,
 }
 
@@ -422,10 +422,10 @@ define_tables! {
     safety: Table<DefIndex, hir::Safety>,
     def_span: Table<DefIndex, LazyValue<Span>>,
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
-    lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
-    lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
-    lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
-    lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
+    lookup_stability: Table<DefIndex, LazyValue<attrs::Stability>>,
+    lookup_const_stability: Table<DefIndex, LazyValue<attrs::ConstStability>>,
+    lookup_default_body_stability: Table<DefIndex, LazyValue<attrs::DefaultBodyStability>>,
+    lookup_deprecation_entry: Table<DefIndex, LazyValue<attrs::Deprecation>>,
     explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
     type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
@@ -480,6 +480,7 @@ define_tables! {
     doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
     assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
     opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
+    anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 5b860374496..2bbc48b633c 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -27,7 +27,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 pub use rustc_type_ir as ir;
-pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
+pub use rustc_type_ir::CanonicalTyVarKind;
 use smallvec::SmallVec;
 
 use crate::mir::ConstraintCategory;
@@ -35,9 +35,9 @@ use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt}
 
 pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
 pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
-pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
+pub type CanonicalVarKind<'tcx> = ir::CanonicalVarKind<TyCtxt<'tcx>>;
 pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
-pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
+pub type CanonicalVarKinds<'tcx> = &'tcx List<CanonicalVarKind<'tcx>>;
 
 /// When we canonicalize a value to form a query, we wind up replacing
 /// various parts of it with canonical variables. This struct stores
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 9912e659b05..454ab8c107f 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -5,7 +5,7 @@ use std::num::NonZero;
 
 use rustc_ast::NodeId;
 use rustc_attr_data_structures::{
-    self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
+    self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
 };
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee};
@@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(Stability {
-                level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by },
+                level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by },
                 feature,
                 ..
             }) => {
@@ -494,7 +494,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(DefaultBodyStability {
-                level: attr::StabilityLevel::Unstable { reason, issue, is_soft, .. },
+                level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, .. },
                 feature,
             }) => {
                 if span.allows_unstable(feature) {
@@ -643,7 +643,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(ConstStability {
-                level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
+                level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
                 feature,
                 ..
             }) => {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 5bd111fa2f2..6035056baaf 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -6,7 +6,7 @@ use rustc_span::ErrorGuaranteed;
 
 use crate::query::CyclePlaceholder;
 use crate::ty::adjustment::CoerceUnsizedInfo;
-use crate::ty::{self, Ty};
+use crate::ty::{self, Ty, TyCtxt};
 use crate::{mir, traits};
 
 #[derive(Copy, Clone)]
@@ -207,6 +207,11 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
     type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
 }
 
+impl EraseType for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
+    type Result =
+        [u8; size_of::<ty::Binder<'static, ty::CoroutineWitnessTypes<TyCtxt<'static>>>>()];
+}
+
 impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
     type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
 }
@@ -311,6 +316,7 @@ trivial! {
     rustc_middle::ty::Asyncness,
     rustc_middle::ty::AsyncDestructor,
     rustc_middle::ty::BoundVariableKind,
+    rustc_middle::ty::AnonConstKind,
     rustc_middle::ty::DeducedParamAttrs,
     rustc_middle::ty::Destructor,
     rustc_middle::ty::fast_reject::SimplifiedType,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b2133fea08c..30245bc82d4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -922,6 +922,12 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    query coroutine_hidden_types(
+        def_id: DefId
+    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
+        desc { "looking up the hidden types stored across await points in a coroutine" }
+    }
+
     /// Gets a map with the variances of every item in the local crate.
     ///
     /// <div class="warning">
@@ -2586,6 +2592,11 @@ rustc_queries! {
         desc { "estimating codegen size of `{}`", key }
         cache_on_disk_if { true }
     }
+
+    query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
+        desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
 }
 
 rustc_with_all_queries! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 5ff87959a80..e0f70737add 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -18,7 +18,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::{Span, SpanDecoder, SpanEncoder};
 
 use crate::arena::ArenaAllocatable;
-use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds};
 use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance};
 use crate::mir::mono::MonoItem;
 use crate::mir::{self};
@@ -310,11 +310,11 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarKinds<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
         decoder.interner().mk_canonical_var_infos_from_iter(
-            (0..len).map::<CanonicalVarInfo<'tcx>, _>(|_| Decodable::decode(decoder)),
+            (0..len).map::<CanonicalVarKind<'tcx>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index dc5fe2d8f8b..455ac660412 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
-use rustc_macros::HashStable;
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_type_ir::walk::TypeWalker;
 use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 
@@ -259,3 +259,16 @@ impl<'tcx> Const<'tcx> {
         TypeWalker::new(self.into())
     }
 }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
+pub enum AnonConstKind {
+    /// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope
+    GCE,
+    /// stable `min_const_generics` anon consts are not allowed to use any generic parameters
+    MCG,
+    /// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters
+    /// but must not depend on the actual instantiation. See #76200 for more information
+    RepeatExprCount,
+    /// anon consts outside of the type system, e.g. enum discriminants
+    NonTypeSystem,
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 0759fa3da42..8c915fea950 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -60,7 +60,7 @@ use tracing::{debug, instrument};
 
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
-use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
+use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, CanonicalVarKinds};
 use crate::lint::lint_level;
 use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
@@ -107,9 +107,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.mk_predefined_opaques_in_body(data)
     }
     type LocalDefIds = &'tcx ty::List<LocalDefId>;
-    type CanonicalVars = CanonicalVarInfos<'tcx>;
-    fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
-        self.mk_canonical_var_infos(infos)
+    type CanonicalVarKinds = CanonicalVarKinds<'tcx>;
+    fn mk_canonical_var_kinds(
+        self,
+        kinds: &[ty::CanonicalVarKind<Self>],
+    ) -> Self::CanonicalVarKinds {
+        self.mk_canonical_var_kinds(kinds)
     }
 
     type ExternalConstraints = ExternalConstraints<'tcx>;
@@ -340,7 +343,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     fn coroutine_hidden_types(
         self,
         def_id: DefId,
-    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
+    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
         self.coroutine_hidden_types(def_id)
     }
 
@@ -833,7 +836,7 @@ pub struct CtxtInterners<'tcx> {
     const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
     args: InternedSet<'tcx, GenericArgs<'tcx>>,
     type_lists: InternedSet<'tcx, List<Ty<'tcx>>>,
-    canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
+    canonical_var_kinds: InternedSet<'tcx, List<CanonicalVarKind<'tcx>>>,
     region: InternedSet<'tcx, RegionKind<'tcx>>,
     poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
     predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
@@ -872,7 +875,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             type_lists: InternedSet::with_capacity(N * 4),
             region: InternedSet::with_capacity(N * 4),
             poly_existential_predicates: InternedSet::with_capacity(N / 4),
-            canonical_var_infos: InternedSet::with_capacity(N / 2),
+            canonical_var_kinds: InternedSet::with_capacity(N / 2),
             predicate: InternedSet::with_capacity(N),
             clauses: InternedSet::with_capacity(N),
             projs: InternedSet::with_capacity(N * 4),
@@ -2675,7 +2678,7 @@ slice_interners!(
     const_lists: pub mk_const_list(Const<'tcx>),
     args: pub mk_args(GenericArg<'tcx>),
     type_lists: pub mk_type_list(Ty<'tcx>),
-    canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
+    canonical_var_kinds: pub mk_canonical_var_kinds(CanonicalVarKind<'tcx>),
     poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
     projs: pub mk_projs(ProjectionKind),
     place_elems: pub mk_place_elems(PlaceElem<'tcx>),
@@ -3055,9 +3058,9 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn mk_canonical_var_infos_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
-        T: CollectAndApply<CanonicalVarInfo<'tcx>, &'tcx List<CanonicalVarInfo<'tcx>>>,
+        T: CollectAndApply<CanonicalVarKind<'tcx>, &'tcx List<CanonicalVarKind<'tcx>>>,
     {
-        T::collect_and_apply(iter, |xs| self.mk_canonical_var_infos(xs))
+        T::collect_and_apply(iter, |xs| self.mk_canonical_var_kinds(xs))
     }
 
     pub fn mk_place_elems_from_iter<I, T>(self, iter: I) -> T::Output
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b2a58897c31..f57329608ef 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -74,8 +74,8 @@ pub use self::closure::{
     place_to_string_for_capture,
 };
 pub use self::consts::{
-    Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
-    Value,
+    AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
+    ValTree, ValTreeKind, Value,
 };
 pub use self::context::{
     CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index ecd6132b3ef..3858778bfc8 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! {
     ty::AsyncDestructor,
     ty::AssocItemContainer,
     ty::Asyncness,
+    ty::AnonConstKind,
     ty::DeducedParamAttrs,
     ty::Destructor,
     ty::Generics,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index ab1f3d6099f..77b9becba57 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1882,9 +1882,9 @@ impl<'tcx> Ty<'tcx> {
             // Needs normalization or revealing to determine, so no is the safe answer.
             ty::Alias(..) => false,
 
-            ty::Param(..) | ty::Infer(..) | ty::Error(..) => false,
+            ty::Param(..) | ty::Placeholder(..) | ty::Infer(..) | ty::Error(..) => false,
 
-            ty::Bound(..) | ty::Placeholder(..) => {
+            ty::Bound(..) => {
                 bug!("`is_trivially_pure_clone_copy` applied to unexpected type: {:?}", self);
             }
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 9676aa40448..ecf83926df7 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -26,7 +26,7 @@ use crate::query::Providers;
 use crate::ty::layout::{FloatExt, IntegerExt};
 use crate::ty::{
     self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
-    TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, fold_regions,
+    TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
 };
 
 #[derive(Copy, Clone, Debug)]
@@ -737,40 +737,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Return the set of types that should be taken into account when checking
-    /// trait bounds on a coroutine's internal state. This properly replaces
-    /// `ReErased` with new existential bound lifetimes.
-    pub fn coroutine_hidden_types(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>> {
-        let coroutine_layout = self.mir_coroutine_witnesses(def_id);
-        let mut vars = vec![];
-        let bound_tys = self.mk_type_list_from_iter(
-            coroutine_layout
-                .as_ref()
-                .map_or_else(|| [].iter(), |l| l.field_tys.iter())
-                .filter(|decl| !decl.ignore_for_traits)
-                .map(|decl| {
-                    let ty = fold_regions(self, decl.ty, |re, debruijn| {
-                        assert_eq!(re, self.lifetimes.re_erased);
-                        let var = ty::BoundVar::from_usize(vars.len());
-                        vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
-                        ty::Region::new_bound(
-                            self,
-                            debruijn,
-                            ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
-                        )
-                    });
-                    ty
-                }),
-        );
-        ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
-            bound_tys,
-            self.mk_bound_variable_kinds(&vars),
-        ))
-    }
-
     /// Expands the given impl trait type, stopping if the type is recursive.
     #[instrument(skip(self), level = "debug", ret)]
     pub fn try_expand_impl_trait_type(
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 9cf051a8760..127b191e335 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -66,8 +66,7 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
                 }
             };
 
-            // this must run before MIR dump, because
-            // "not all control paths return a value" is reported here.
+            // Checking liveness after building the THIR ensures there were no typeck errors.
             //
             // maybe move the check to a MIR pass?
             tcx.ensure_ok().check_liveness(def);
@@ -451,10 +450,6 @@ fn construct_fn<'tcx>(
     let span = tcx.def_span(fn_def);
     let fn_id = tcx.local_def_id_to_hir_id(fn_def);
 
-    // The representation of thir for `-Zunpretty=thir-tree` relies on
-    // the entry expression being the last element of `thir.exprs`.
-    assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
-
     // Figure out what primary body this item has.
     let body = tcx.hir_body_owned_by(fn_def);
     let span_with_body = tcx.hir_span_with_body(fn_id);
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 2f593b9a0a7..8c817605847 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -27,8 +27,8 @@ pub(crate) fn thir_body(
     if let Some(reported) = cx.typeck_results.tainted_by_errors {
         return Err(reported);
     }
-    let expr = cx.mirror_expr(body.value);
 
+    // Lower the params before the body's expression so errors from params are shown first.
     let owner_id = tcx.local_def_id_to_hir_id(owner_def);
     if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(owner_id) {
         let closure_env_param = cx.closure_env_param(owner_def, owner_id);
@@ -48,6 +48,7 @@ pub(crate) fn thir_body(
         }
     }
 
+    let expr = cx.mirror_expr(body.value);
     Ok((tcx.alloc_steal_thir(cx.thir), expr))
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index b7d203e3cd7..e233358f386 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -382,6 +382,9 @@ fn extend_type_not_partial_eq<'tcx>(
         fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
             match ty.kind() {
                 ty::Dynamic(..) => return ControlFlow::Break(()),
+                // Unsafe binders never implement `PartialEq`, so avoid walking into them
+                // which would require instantiating its binder with placeholders too.
+                ty::UnsafeBinder(..) => return ControlFlow::Break(()),
                 ty::FnPtr(..) => return ControlFlow::Continue(()),
                 ty::Adt(def, _args) => {
                     let ty_def_id = def.did();
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 37248941e2c..db9547a481f 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -8,10 +8,10 @@ use rustc_span::def_id::LocalDefId;
 /// Create a THIR tree for debugging.
 pub fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
     match super::cx::thir_body(tcx, owner_def) {
-        Ok((thir, _)) => {
+        Ok((thir, expr)) => {
             let thir = thir.steal();
             let mut printer = ThirPrinter::new(&thir);
-            printer.print();
+            printer.print(expr);
             printer.into_buffer()
         }
         Err(_) => "error".into(),
@@ -58,7 +58,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
         }
     }
 
-    fn print(&mut self) {
+    fn print(&mut self, body_expr: ExprId) {
         print_indented!(self, "params: [", 0);
         for param in self.thir.params.iter() {
             self.print_param(param, 1);
@@ -66,8 +66,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
         print_indented!(self, "]", 0);
 
         print_indented!(self, "body:", 0);
-        let expr = ExprId::from_usize(self.thir.exprs.len() - 1);
-        self.print_expr(expr, 1);
+        self.print_expr(body_expr, 1);
     }
 
     fn into_buffer(self) -> String {
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 9e4b4534dcc..a7d0b3acbe4 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -10,7 +10,7 @@ itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_const_eval = { path = "../rustc_const_eval" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_mir_transform/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs
index 83c3cda5a50..14d9532894f 100644
--- a/compiler/rustc_mir_transform/src/check_inline.rs
+++ b/compiler/rustc_mir_transform/src/check_inline.rs
@@ -1,7 +1,7 @@
 //! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its
 //! definition alone (irrespective of any specific caller).
 
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::{Body, TerminatorKind};
diff --git a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
index 8da17a056e3..1a3715465ad 100644
--- a/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
+++ b/compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
@@ -9,6 +9,7 @@ use crate::errors::UnnecessaryTransmute as Error;
 
 /// Check for transmutes that overlap with stdlib methods.
 /// For example, transmuting `[u8; 4]` to `u32`.
+/// We chose not to lint u8 -> bool transmutes, see #140431
 pub(super) struct CheckUnnecessaryTransmutes;
 
 impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes {
@@ -29,6 +30,7 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
         function: &Operand<'tcx>,
         arg: String,
         span: Span,
+        is_in_const: bool,
     ) -> Option<Error> {
         let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
         let [input] = fn_sig.inputs() else { return None };
@@ -96,10 +98,14 @@ impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
             )),
             // uNN → fNN
             (Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())),
-            // bool → { x8 }
-            (Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())),
-            // u8 → bool
-            (Uint(_), Bool) => err(format!("({arg} == 1)")),
+            // bool → { x8 } in const context since `From::from` is not const yet
+            // FIXME: is it possible to know when the parentheses arent necessary?
+            // FIXME(const_traits): Remove this when From::from is constified?
+            (Bool, Int(..) | Uint(..)) if is_in_const => {
+                err(format!("({arg}) as {}", fn_sig.output()))
+            }
+            // " using `x8::from`
+            (Bool, Int(..) | Uint(..)) => err(format!("{}::from({arg})", fn_sig.output())),
             _ => return None,
         })
     }
@@ -115,7 +121,13 @@ impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> {
             && self.tcx.is_intrinsic(func_def_id, sym::transmute)
             && let span = self.body.source_info(location).span
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(arg)
-            && let Some(lint) = self.is_unnecessary_transmute(func, snippet, span)
+            && let def_id = self.body.source.def_id()
+            && let Some(lint) = self.is_unnecessary_transmute(
+                func,
+                snippet,
+                span,
+                self.tcx.hir_body_const_context(def_id.expect_local()).is_some(),
+            )
             && let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes)
         {
             self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint);
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index ec76076020e..ddeae093df5 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,7 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span};
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span};
 use tracing::instrument;
 
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
@@ -83,8 +84,18 @@ pub(super) fn extract_refined_covspans<'tcx>(
     // Discard any span that overlaps with a hole.
     discard_spans_overlapping_holes(&mut covspans, &holes);
 
-    // Perform more refinement steps after holes have been dealt with.
+    // Discard spans that overlap in unwanted ways.
     let mut covspans = remove_unwanted_overlapping_spans(covspans);
+
+    // For all empty spans, either enlarge them to be non-empty, or discard them.
+    let source_map = tcx.sess.source_map();
+    covspans.retain_mut(|covspan| {
+        let Some(span) = ensure_non_empty_span(source_map, covspan.span) else { return false };
+        covspan.span = span;
+        true
+    });
+
+    // Merge covspans that can be merged.
     covspans.dedup_by(|b, a| a.merge_if_eligible(b));
 
     code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
@@ -230,3 +241,26 @@ fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering {
         // - Both have the same start and span A extends further right
         .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse())
 }
+
+fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
+    if !span.is_empty() {
+        return Some(span);
+    }
+
+    // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
+    source_map
+        .span_to_source(span, |src, start, end| try {
+            // Adjusting span endpoints by `BytePos(1)` is normally a bug,
+            // but in this case we have specifically checked that the character
+            // we're skipping over is one of two specific ASCII characters, so
+            // adjusting by exactly 1 byte is correct.
+            if src.as_bytes().get(end).copied() == Some(b'{') {
+                Some(span.with_hi(span.hi() + BytePos(1)))
+            } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(span.lo() - BytePos(1)))
+            } else {
+                None
+            }
+        })
+        .ok()?
+}
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 4f45d9588a8..727d4a126d2 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -1,4 +1,4 @@
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::visit::Visitor;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 73a58160a6a..14f7c2a263b 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -251,7 +251,29 @@ where
                     span_bug!(span, "invalid `AsyncDrop` impl_source: {:?}", impl_source);
                 }
             };
-            let drop_fn_def_id = tcx.associated_item_def_ids(drop_trait)[0];
+            // impl_item_refs may be empty if drop fn is not implemented in 'impl AsyncDrop for ...'
+            // (#140974).
+            // Such code will report error, so just generate sync drop here and return
+            let Some(drop_fn_def_id) =
+                tcx.associated_item_def_ids(drop_trait).into_iter().nth(0).copied()
+            else {
+                tcx.dcx().span_delayed_bug(
+                    self.elaborator.body().span,
+                    "AsyncDrop type without correct `async fn drop(...)`.",
+                );
+                self.elaborator.patch().patch_terminator(
+                    pin_obj_bb,
+                    TerminatorKind::Drop {
+                        place,
+                        target: succ,
+                        unwind: unwind.into_action(),
+                        replace: false,
+                        drop: None,
+                        async_fut: None,
+                    },
+                );
+                return pin_obj_bb;
+            };
             let drop_fn = Ty::new_fn_def(tcx, drop_fn_def_id, trait_args);
             let sig = drop_fn.fn_sig(tcx);
             let sig = tcx.instantiate_bound_regions_with_erased(sig);
@@ -318,15 +340,20 @@ where
                 bug!();
             };
             let obj_ptr_ty = Ty::new_mut_ptr(tcx, drop_ty);
-            let obj_ptr_place = Place::from(self.new_temp(obj_ptr_ty));
             let unwrap_ty = adt_def.non_enum_variant().fields[FieldIdx::ZERO].ty(tcx, adt_args);
-            let addr = Rvalue::RawPtr(
-                RawPtrKind::Mut,
-                pin_obj_place.project_deeper(
-                    &[ProjectionElem::Field(FieldIdx::ZERO, unwrap_ty), ProjectionElem::Deref],
-                    tcx,
-                ),
-            );
+            let obj_ref_place = Place::from(self.new_temp(unwrap_ty));
+            call_statements.push(self.assign(
+                obj_ref_place,
+                Rvalue::Use(Operand::Copy(tcx.mk_place_field(
+                    pin_obj_place,
+                    FieldIdx::ZERO,
+                    unwrap_ty,
+                ))),
+            ));
+
+            let obj_ptr_place = Place::from(self.new_temp(obj_ptr_ty));
+
+            let addr = Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_deref(obj_ref_place));
             call_statements.push(self.assign(obj_ptr_place, addr));
             obj_ptr_place
         };
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 9785c039d53..f48dba9663a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -5,7 +5,7 @@ use std::iter;
 use std::ops::{Range, RangeFrom};
 
 use rustc_abi::{ExternAbi, FieldIdx};
-use rustc_attr_parsing::{InlineAttr, OptimizeAttr};
+use rustc_attr_data_structures::{InlineAttr, OptimizeAttr};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index 7976b65aae7..fbc8ee9b06c 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -6,7 +6,7 @@ use rustc_middle::mir::{
     BasicBlock, BasicBlockData, Body, Local, LocalDecl, MirSource, Operand, Place, Rvalue,
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
 };
-use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt};
 
 use super::*;
 use crate::patch::MirPatch;
@@ -121,9 +121,10 @@ pub(super) fn build_async_drop_shim<'tcx>(
         parent_args.as_coroutine().resume_ty(),
     )));
     body.phase = MirPhase::Runtime(RuntimePhase::Initial);
-    if !needs_async_drop {
+    if !needs_async_drop || drop_ty.references_error() {
         // Returning noop body for types without `need async drop`
-        // (or sync Drop in case of !`need async drop` && `need drop`)
+        // (or sync Drop in case of !`need async drop` && `need drop`).
+        // And also for error types.
         return body;
     }
 
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index f8d1629b0e2..c8aa7588d03 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1,7 +1,7 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
 use rustc_abi::{ExternAbi, FIRST_VARIANT, Size};
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::LangItem;
 use rustc_index::IndexVec;
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
index 36b76d261de..063fc8f1c74 100644
--- a/compiler/rustc_monomorphize/Cargo.toml
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2024"
 # tidy-alphabetical-start
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index c6a81e60b2b..b3d7eaf332b 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -208,7 +208,7 @@
 use std::cell::OnceCell;
 use std::path::PathBuf;
 
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{MTLock, par_for_each_in};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index c3a41529794..b4169a060d4 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -100,6 +100,7 @@ use std::fs::{self, File};
 use std::io::Write;
 use std::path::{Path, PathBuf};
 
+use rustc_attr_data_structures::InlineAttr;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sync;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
@@ -845,8 +846,7 @@ fn mono_item_visibility<'tcx>(
         return if is_generic
             && (always_export_generics
                 || (can_export_generics
-                    && tcx.codegen_fn_attrs(def_id).inline
-                        == rustc_attr_parsing::InlineAttr::Never))
+                    && tcx.codegen_fn_attrs(def_id).inline == InlineAttr::Never))
         {
             // If it is an upstream monomorphization and we export generics, we must make
             // it available to downstream crates.
@@ -859,8 +859,7 @@ fn mono_item_visibility<'tcx>(
 
     if is_generic {
         if always_export_generics
-            || (can_export_generics
-                && tcx.codegen_fn_attrs(def_id).inline == rustc_attr_parsing::InlineAttr::Never)
+            || (can_export_generics && tcx.codegen_fn_attrs(def_id).inline == InlineAttr::Never)
         {
             if tcx.is_unreachable_local_definition(def_id) {
                 // This instance cannot be used from another crate.
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index bbb4a162027..93b8940ee37 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -4,8 +4,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::solve::{Goal, QueryInput};
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
-    Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, InferCtxtLike, Interner,
+    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 
 use crate::delegate::SolverDelegate;
@@ -50,7 +50,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
 
     // Mutable fields.
     variables: &'a mut Vec<I::GenericArg>,
-    primitive_var_infos: Vec<CanonicalVarInfo<I>>,
+    var_kinds: Vec<CanonicalVarKind<I>>,
     variable_lookup_table: HashMap<I::GenericArg, usize>,
     binder_index: ty::DebruijnIndex,
 
@@ -73,7 +73,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
             variables,
             variable_lookup_table: Default::default(),
-            primitive_var_infos: Vec::new(),
+            var_kinds: Vec::new(),
             binder_index: ty::INNERMOST,
 
             cache: Default::default(),
@@ -106,7 +106,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
             variables,
             variable_lookup_table: Default::default(),
-            primitive_var_infos: Vec::new(),
+            var_kinds: Vec::new(),
             binder_index: ty::INNERMOST,
 
             cache: Default::default(),
@@ -123,7 +123,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             // We're able to reuse the `variable_lookup_table` as whether or not
             // it already contains an entry for `'static` does not matter.
             variable_lookup_table: env_canonicalizer.variable_lookup_table,
-            primitive_var_infos: env_canonicalizer.primitive_var_infos,
+            var_kinds: env_canonicalizer.var_kinds,
             binder_index: ty::INNERMOST,
 
             // We do not reuse the cache as it may contain entries whose canonicalized
@@ -149,7 +149,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
     fn get_or_insert_bound_var(
         &mut self,
         arg: impl Into<I::GenericArg>,
-        canonical_var_info: CanonicalVarInfo<I>,
+        kind: CanonicalVarKind<I>,
     ) -> ty::BoundVar {
         // FIXME: 16 is made up and arbitrary. We should look at some
         // perf data here.
@@ -162,14 +162,14 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             *self.variable_lookup_table.entry(arg).or_insert_with(|| {
                 let var = self.variables.len();
                 self.variables.push(arg);
-                self.primitive_var_infos.push(canonical_var_info);
+                self.var_kinds.push(kind);
                 var
             })
         } else {
             self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| {
                 let var = self.variables.len();
                 self.variables.push(arg);
-                self.primitive_var_infos.push(canonical_var_info);
+                self.var_kinds.push(kind);
                 var
             })
         };
@@ -177,8 +177,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         ty::BoundVar::from(idx)
     }
 
-    fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
-        let mut var_infos = self.primitive_var_infos;
+    fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) {
+        let mut var_kinds = self.var_kinds;
         // See the rustc-dev-guide section about how we deal with universes
         // during canonicalization in the new solver.
         match self.canonicalize_mode {
@@ -192,25 +192,25 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             // information for placeholders and inference variables created inside
             // of the query.
             CanonicalizeMode::Response { max_input_universe } => {
-                for var in var_infos.iter_mut() {
+                for var in var_kinds.iter_mut() {
                     let uv = var.universe();
                     let new_uv = ty::UniverseIndex::from(
                         uv.index().saturating_sub(max_input_universe.index()),
                     );
                     *var = var.with_updated_universe(new_uv);
                 }
-                let max_universe = var_infos
+                let max_universe = var_kinds
                     .iter()
-                    .map(|info| info.universe())
+                    .map(|kind| kind.universe())
                     .max()
                     .unwrap_or(ty::UniverseIndex::ROOT);
 
-                let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
-                return (max_universe, var_infos);
+                let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
+                return (max_universe, var_kinds);
             }
         }
 
-        // Given a `var_infos` with existentials `En` and universals `Un` in
+        // Given a `var_kinds` with existentials `En` and universals `Un` in
         // universes `n`, this algorithm compresses them in place so that:
         //
         // - the new universe indices are as small as possible
@@ -219,12 +219,12 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         //   2. put a placeholder in the same universe as an existential which cannot name it
         //
         // Let's walk through an example:
-        // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
-        // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
-        // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
-        // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
-        // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
-        // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
+        // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
+        // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
+        // - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
+        // - var_kinds: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
+        // - var_kinds: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
+        // - var_kinds: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
         //
         // This algorithm runs in `O(mn)` where `n` is the number of different universes and
         // `m` the number of variables. This should be fine as both are expected to be small.
@@ -232,7 +232,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         let mut existential_in_new_uv = None;
         let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
         while let Some(orig_uv) = next_orig_uv.take() {
-            let mut update_uv = |var: &mut CanonicalVarInfo<I>, orig_uv, is_existential| {
+            let mut update_uv = |var: &mut CanonicalVarKind<I>, orig_uv, is_existential| {
                 let uv = var.universe();
                 match uv.cmp(&orig_uv) {
                     Ordering::Less => (), // Already updated
@@ -284,7 +284,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             // Whenever we compress the universe of a placeholder, no existential with
             // an already compressed universe can name that placeholder.
             for is_existential in [false, true] {
-                for var in var_infos.iter_mut() {
+                for var in var_kinds.iter_mut() {
                     // We simply put all regions from the input into the highest
                     // compressed universe, so we only deal with them at the end.
                     if !var.is_region() {
@@ -298,7 +298,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
         // We put all regions into a separate universe.
         let mut first_region = true;
-        for var in var_infos.iter_mut() {
+        for var in var_kinds.iter_mut() {
             if var.is_region() {
                 if first_region {
                     first_region = false;
@@ -309,8 +309,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             }
         }
 
-        let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
-        (curr_compressed_uv, var_infos)
+        let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
+        (curr_compressed_uv, var_kinds)
     }
 
     fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty {
@@ -391,7 +391,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             }
         };
 
-        let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind });
+        let var = self.get_or_insert_bound_var(t, kind);
 
         Ty::new_anon_bound(self.cx(), self.binder_index, var)
     }
@@ -475,7 +475,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             }
         };
 
-        let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind });
+        let var = self.get_or_insert_bound_var(r, kind);
 
         Region::new_anon_bound(self.cx(), self.binder_index, var)
     }
@@ -525,7 +525,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
             | ty::ConstKind::Expr(_) => return c.super_fold_with(self),
         };
 
-        let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind });
+        let var = self.get_or_insert_bound_var(c, kind);
 
         Const::new_anon_bound(self.cx(), self.binder_index, var)
     }
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 90a7c2e9f78..32dc85b3e6a 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -3,6 +3,8 @@ use std::ops::Deref;
 use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
 use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable};
 
+use crate::solve::HasChanged;
+
 pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
     type Infcx: InferCtxtLike<Interner = Self::Interner>;
     type Interner: Interner;
@@ -17,6 +19,12 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
     where
         V: TypeFoldable<Self::Interner>;
 
+    fn compute_goal_fast_path(
+        &self,
+        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
+        span: <Self::Interner as Interner>::Span,
+    ) -> Option<HasChanged>;
+
     fn fresh_var_for_kind_with_span(
         &self,
         arg: <Self::Interner as Interner>::GenericArg,
@@ -53,7 +61,7 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
 
     fn instantiate_canonical_var_with_infer(
         &self,
-        cv_info: ty::CanonicalVarInfo<Self::Interner>,
+        kind: ty::CanonicalVarKind<Self::Interner>,
         span: <Self::Interner as Interner>::Span,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> <Self::Interner as Interner>::GenericArg;
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 2a2b462a36c..4a2a7761f7f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -83,7 +83,7 @@ where
             .cx()
             .coroutine_hidden_types(def_id)
             .instantiate(cx, args)
-            .map_bound(|tys| tys.to_vec())),
+            .map_bound(|bound| bound.types.to_vec())),
 
         ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
 
@@ -249,7 +249,7 @@ where
             .cx()
             .coroutine_hidden_types(def_id)
             .instantiate(ecx.cx(), args)
-            .map_bound(|tys| tys.to_vec())),
+            .map_bound(|bound| bound.types.to_vec())),
     }
 }
 
@@ -327,7 +327,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
                 // always be called once. It additionally implements `Fn`/`FnMut`
                 // only if it has no upvars referencing the closure-env lifetime,
                 // and if the closure kind permits it.
-                if closure_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
+                if goal_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
                     return Err(NoSolution);
                 }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 36f68808a2c..455a178595b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -12,6 +12,7 @@
 use std::iter;
 
 use rustc_index::IndexVec;
+use rustc_type_ir::data_structures::HashSet;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::{
@@ -158,10 +159,12 @@ where
             self.compute_external_query_constraints(certainty, normalization_nested_goals);
         let (var_values, mut external_constraints) = (self.var_values, external_constraints)
             .fold_with(&mut EagerResolver::new(self.delegate));
-        // Remove any trivial region constraints once we've resolved regions
-        external_constraints
-            .region_constraints
-            .retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1));
+
+        // Remove any trivial or duplicated region constraints once we've resolved regions
+        let mut unique = HashSet::default();
+        external_constraints.region_constraints.retain(|outlives| {
+            outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives)
+        });
 
         let canonical = Canonicalizer::canonicalize_response(
             self.delegate,
@@ -357,15 +360,15 @@ where
         }
 
         let var_values = delegate.cx().mk_args_from_iter(
-            response.variables.iter().enumerate().map(|(index, info)| {
-                if info.universe() != ty::UniverseIndex::ROOT {
+            response.variables.iter().enumerate().map(|(index, var_kind)| {
+                if var_kind.universe() != ty::UniverseIndex::ROOT {
                     // A variable from inside a binder of the query. While ideally these shouldn't
                     // exist at all (see the FIXME at the start of this method), we have to deal with
                     // them for now.
-                    delegate.instantiate_canonical_var_with_infer(info, span, |idx| {
+                    delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| {
                         prev_universe + idx.index()
                     })
-                } else if info.is_existential() {
+                } else if var_kind.is_existential() {
                     // As an optimization we sometimes avoid creating a new inference variable here.
                     //
                     // All new inference variables we create start out in the current universe of the caller.
@@ -376,12 +379,13 @@ where
                     if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
                         v
                     } else {
-                        delegate.instantiate_canonical_var_with_infer(info, span, |_| prev_universe)
+                        delegate
+                            .instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe)
                     }
                 } else {
                     // For placeholders which were already part of the input, we simply map this
                     // universal bound variable back the placeholder of the input.
-                    original_values[info.expect_placeholder_index()]
+                    original_values[var_kind.expect_placeholder_index()]
                 }
             }),
         );
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index fc5dad9a3ed..dfabb94ebfc 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -91,7 +91,7 @@ where
 
     /// The variable info for the `var_values`, only used to make an ambiguous response
     /// with no constraints.
-    variables: I::CanonicalVars,
+    variables: I::CanonicalVarKinds,
 
     /// What kind of goal we're currently computing, see the enum definition
     /// for more info.
@@ -603,6 +603,14 @@ where
         // If this loop did not result in any progress, what's our final certainty.
         let mut unchanged_certainty = Some(Certainty::Yes);
         for (source, goal) in mem::take(&mut self.nested_goals) {
+            if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span)
+            {
+                if matches!(has_changed, HasChanged::Yes) {
+                    unchanged_certainty = None;
+                }
+                continue;
+            }
+
             // We treat normalizes-to goals specially here. In each iteration we take the
             // RHS of the projection, replace it with a fresh inference variable, and only
             // after evaluating that goal do we equate the fresh inference variable with the
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 8173146e2fe..2a641807154 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -354,7 +354,7 @@ where
 fn response_no_constraints_raw<I: Interner>(
     cx: I,
     max_universe: ty::UniverseIndex,
-    variables: I::CanonicalVars,
+    variables: I::CanonicalVarKinds,
     certainty: Certainty,
 ) -> CanonicalResponse<I> {
     ty::Canonical {
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 966d5422fbb..7c4e1dc2c12 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -9,7 +9,7 @@ use rustc_type_ir::{
     self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
     Upcast as _, elaborate,
 };
-use tracing::{instrument, trace};
+use tracing::{debug, instrument, trace};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
@@ -17,7 +17,7 @@ use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidates
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, ParamEnvSource, QueryResult,
+    NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
 };
 
 impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
@@ -1253,6 +1253,45 @@ where
     D: SolverDelegate<Interner = I>,
     I: Interner,
 {
+    /// FIXME(#57893): For backwards compatability with the old trait solver implementation,
+    /// we need to handle overlap between builtin and user-written impls for trait objects.
+    ///
+    /// This overlap is unsound in general and something which we intend to fix separately.
+    /// To avoid blocking the stabilization of the trait solver, we add this hack to avoid
+    /// breakage in cases which are *mostly fine*™. Importantly, this preference is strictly
+    /// weaker than the old behavior.
+    ///
+    /// We only prefer builtin over user-written impls if there are no inference constraints.
+    /// Importantly, we also only prefer the builtin impls for trait goals, and not during
+    /// normalization. This means the only case where this special-case results in exploitable
+    /// unsoundness should be lifetime dependent user-written impls.
+    pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
+        match self.typing_mode() {
+            TypingMode::Coherence => return,
+            TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. }
+            | TypingMode::PostAnalysis => {}
+        }
+
+        if candidates
+            .iter()
+            .find(|c| {
+                matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
+            })
+            .is_some_and(|c| has_only_region_constraints(c.result))
+        {
+            candidates.retain(|c| {
+                if matches!(c.source, CandidateSource::Impl(_)) {
+                    debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
+                    false
+                } else {
+                    true
+                }
+            });
+        }
+    }
+
     #[instrument(level = "debug", skip(self), ret)]
     pub(super) fn merge_trait_candidates(
         &mut self,
@@ -1313,6 +1352,7 @@ where
         }
 
         self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
+        self.unsound_prefer_builtin_dyn_impl(&mut candidates);
 
         // If there are *only* global where bounds, then make sure to return that this
         // is still reported as being proven-via the param-env so that rigid projections
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index ba81ef3103b..b9167489076 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -9,7 +9,7 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_expand = { path = "../rustc_expand" }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c68f8df49fc..1d024694049 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,7 @@ use std::collections::hash_map::Entry;
 
 use rustc_abi::{Align, ExternAbi, Size};
 use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
-use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr};
+use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
 use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
@@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{
     UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
 use rustc_session::parse::feature_err;
-use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym};
+use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
 use rustc_trait_selection::traits::ObligationCtxt;
@@ -936,7 +936,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
         let attr_str =
             &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
-        if doc_alias == kw::Empty {
+        if doc_alias == sym::empty {
             tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
             return;
         }
@@ -1068,7 +1068,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
 
         let doc_keyword = match meta.value_str() {
-            Some(value) if value != kw::Empty => value,
+            Some(value) if value != sym::empty => value,
             _ => return self.doc_attr_str_error(meta, "keyword"),
         };
 
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 7353c1ead5a..b3e6ee9512c 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -4,7 +4,7 @@
 //! but are not declared in one single location (unlike lang features), which means we need to
 //! collect them instead.
 
-use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince};
+use rustc_attr_data_structures::{AttributeKind, StabilityLevel, StableSince};
 use rustc_hir::Attribute;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 4e9b7fd44d4..763d9fda804 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -122,7 +122,6 @@ enum LiveNodeKind {
     VarDefNode(Span, HirId),
     ClosureNode,
     ExitNode,
-    ErrNode,
 }
 
 fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
@@ -133,7 +132,6 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
         VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)),
         ClosureNode => "Closure node".to_owned(),
         ExitNode => "Exit node".to_owned(),
-        ErrNode => "Error node".to_owned(),
     }
 }
 
@@ -492,6 +490,9 @@ struct Liveness<'a, 'tcx> {
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
         let typeck_results = ir.tcx.typeck(body_owner);
+        // Liveness linting runs after building the THIR. We make several assumptions based on
+        // typeck succeeding, e.g. that breaks and continues are well-formed.
+        assert!(typeck_results.tainted_by_errors.is_none());
         // FIXME(#132279): we're in a body here.
         let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner);
         let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner);
@@ -976,8 +977,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 // Now that we know the label we're going to,
                 // look it up in the continue loop nodes table
                 self.cont_ln.get(&sc).cloned().unwrap_or_else(|| {
-                    self.ir.tcx.dcx().span_delayed_bug(expr.span, "continue to unknown label");
-                    self.ir.add_live_node(ErrNode)
+                    // Liveness linting happens after building the THIR. Bad labels should already
+                    // have been caught.
+                    span_bug!(expr.span, "continue to unknown label");
                 })
             }
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index d7baad69c78..9884386d68f 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -5,9 +5,9 @@ use std::mem::replace;
 use std::num::NonZero;
 
 use rustc_ast_lowering::stability::extern_abi_stability;
-use rustc_attr_parsing::{
-    self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability,
-    StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
+use rustc_attr_data_structures::{
+    self as attrs, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability,
+    Stability, StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
 };
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
@@ -121,7 +121,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
 
-        let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
+        let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
         let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
 
         let mut is_deprecated = false;
@@ -174,9 +174,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         }
 
         // # Regular and body stability
-        let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
+        let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
         let body_stab =
-            attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
+            attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
 
         if let Some((depr, span)) = &depr
             && depr.is_since_rustc_version()
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             // this is *almost surely* an accident.
             if let (
                 &Some(DeprecatedSince::RustcVersion(dep_since)),
-                &attr::StabilityLevel::Stable { since: stab_since, .. },
+                &attrs::StabilityLevel::Stable { since: stab_since, .. },
             ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
             {
                 match stab_since {
@@ -263,7 +263,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
 
         // # Const stability
 
-        let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
+        let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
 
         // If the current node is a function with const stability attributes (directly given or
         // implied), check if the function/method is const or the parent impl block is const.
@@ -713,7 +713,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
         // by default and are unable to be used.
         if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
             let stability = Stability {
-                level: attr::StabilityLevel::Unstable {
+                level: attrs::StabilityLevel::Unstable {
                     reason: UnstableReason::Default,
                     issue: NonZero::new(27812),
                     is_soft: false,
@@ -796,17 +796,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 let features = self.tcx.features();
                 if features.staged_api() {
                     let attrs = self.tcx.hir_attrs(item.hir_id());
-                    let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
+                    let stab = attrs::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
 
                     // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
-                    let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
+                    let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
 
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
                     // it will have no effect.
                     // See: https://github.com/rust-lang/rust/issues/55436
                     if let Some((
-                        Stability { level: attr::StabilityLevel::Unstable { .. }, .. },
+                        Stability { level: attrs::StabilityLevel::Unstable { .. }, .. },
                         span,
                     )) = stab
                     {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index a89d01dcbbe..d9f1888bfd9 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,6 +1,5 @@
 use std::fmt;
 use std::iter::once;
-use std::ops::ControlFlow;
 
 use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
 use rustc_arena::DroplessArena;
@@ -12,8 +11,7 @@ use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, VariantDef,
+    self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -137,22 +135,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Returns the hidden type corresponding to this key if the body under analysis is allowed to
     /// know it.
     fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
-        if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) {
-            let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args);
-            if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() {
-                Some(ty)
-            } else {
-                // HACK: We skip revealing opaque types which recursively expand
-                // to themselves. This is because we may infer hidden types like
-                // `Opaque<T> = Opaque<Opaque<T>>` or `Opaque<T> = Opaque<(T,)>`
-                // in hir typeck.
-                None
-            }
-        } else {
-            None
-        }
+        self.typeck_results
+            .concrete_opaque_types
+            .get(&key.def_id)
+            .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
     }
-
     // This can take a non-revealed `Ty` because it reveals opaques itself.
     pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
         !ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
@@ -1177,20 +1164,3 @@ fn detect_mixed_deref_pat_ctors<'p, 'tcx>(
     }
     Ok(())
 }
-
-struct RecursiveOpaque {
-    def_id: DefId,
-}
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveOpaque {
-    type Result = ControlFlow<()>;
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
-        if let ty::Alias(ty::Opaque, alias_ty) = t.kind() {
-            if alias_ty.def_id == self.def_id {
-                return ControlFlow::Break(());
-            }
-        }
-
-        if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) }
-    }
-}
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 242c67d732a..109a7bf49fe 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_parsing = { path = "../rustc_attr_parsing" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9c2921cd5b2..e2dfaec61b3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -20,7 +20,6 @@ use errors::{
 };
 use rustc_ast::MacroDef;
 use rustc_ast::visit::{VisitorResult, try_visit};
-use rustc_attr_parsing::AttributeKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{MultiSpan, listify};
@@ -40,7 +39,7 @@ use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::{Ident, Span, Symbol, sym};
 use tracing::debug;
-use {rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_attr_data_structures as attrs, rustc_hir as hir};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
@@ -497,7 +496,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
         let attrs = self.tcx.hir_attrs(hir_id);
 
-        if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
+        if attrs::find_attr!(attrs, attrs::AttributeKind::MacroTransparency(x) => *x)
             .unwrap_or(Transparency::fallback(md.macro_rules))
             != Transparency::Opaque
         {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 3ae56cef2c4..d4217e0aa54 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1433,6 +1433,8 @@ fn panic_on_forbidden_read<D: Deps>(data: &DepGraphData<D>, dep_node_index: DepN
         && let Some(nodes) = &data.current.nodes_in_current_session
     {
         // Try to find it among the nodes allocated so far in this session
+        // This is OK, there's only ever one node result possible so this is deterministic.
+        #[allow(rustc::potential_query_instability)]
         if let Some((node, _)) = nodes.lock().iter().find(|&(_, index)| *index == dep_node_index) {
             dep_node = Some(*node);
         }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index f1b609a3ca9..79b99c52d0c 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -784,6 +784,8 @@ impl<D: Deps> EncoderState<D> {
     ) {
         if let Some(record_stats) = &self.stats {
             let record_stats = record_stats.lock();
+            // `stats` is sorted below so we can allow this lint here.
+            #[allow(rustc::potential_query_instability)]
             let mut stats: Vec<_> = record_stats.values().collect();
             stats.sort_by_key(|s| -(s.node_counter as i64));
 
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index eba7378b475..d36cb6f0e5b 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,5 +1,5 @@
 // tidy-alphabetical-start
-#![allow(rustc::potential_query_instability, internal_features)]
+#![allow(internal_features)]
 #![feature(assert_matches)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 6321abc5087..1e79bd461d2 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -510,6 +510,10 @@ pub fn break_query_cycles<I: Clone + Debug>(
     registry: &rayon_core::Registry,
 ) {
     let mut wakelist = Vec::new();
+    // It is OK per the comments:
+    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932
+    // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798866392
+    #[allow(rustc::potential_query_instability)]
     let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
 
     let mut found_cycle = false;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1b682d0cf8a..fd977a8eb6c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3901,7 +3901,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // We walk the pattern before declaring the pattern's inner bindings,
         // so that we avoid resolving a literal expression to a binding defined
         // by the pattern.
-        visit::walk_pat(self, pat);
+        // NB: `Self::visit_pat` must be used rather than `visit::walk_pat` to avoid resolving guard
+        // patterns' guard expressions multiple times (#141265).
+        self.visit_pat(pat);
         self.resolve_pattern_inner(pat, pat_src, bindings);
         // This has to happen *after* we determine which pat_idents are variants:
         self.check_consistent_bindings(pat);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index b538be34f31..ca25cdc9563 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -11,6 +11,7 @@ use rustc_ast::{
     Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
+use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
@@ -39,7 +40,7 @@ use crate::late::{
 };
 use crate::ty::fast_reject::SimplifiedType;
 use crate::{
-    Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors,
+    Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors,
     path_names_to_string,
 };
 
@@ -477,6 +478,19 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             return (err, Vec::new());
         }
 
+        if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) {
+            let item_name = item.name;
+            let suggestion_name = self.r.tcx.item_name(did);
+            err.span_suggestion(
+                item.span,
+                format!("`{suggestion_name}` has a name defined in the doc alias attribute as `{item_name}`"),
+                    suggestion_name,
+                    Applicability::MaybeIncorrect
+                );
+
+            return (err, Vec::new());
+        };
+
         let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(
             &mut err,
             source,
@@ -751,12 +765,24 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 match candidate {
                     AssocSuggestion::Field(field_span) => {
                         if self_is_available {
-                            err.span_suggestion_verbose(
-                                span.shrink_to_lo(),
-                                "you might have meant to use the available field",
-                                format!("{pre}self."),
-                                Applicability::MachineApplicable,
-                            );
+                            let source_map = self.r.tcx.sess.source_map();
+                            // check if the field is used in a format string, such as `"{x}"`
+                            let field_is_format_named_arg = source_map
+                                .span_to_source(span, |s, start, _| {
+                                    Ok(s.get(start - 1..start) == Some("{"))
+                                });
+                            if let Ok(true) = field_is_format_named_arg {
+                                err.help(
+                                    format!("you might have meant to use the available field in a format string: `\"{{}}\", self.{}`", segment.ident.name),
+                                );
+                            } else {
+                                err.span_suggestion_verbose(
+                                    span.shrink_to_lo(),
+                                    "you might have meant to use the available field",
+                                    format!("{pre}self."),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         } else {
                             err.span_label(field_span, "a field by that name exists in `Self`");
                         }
@@ -852,6 +878,65 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         (false, suggested_candidates, candidates)
     }
 
+    fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> {
+        let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| {
+            for resolution in r.resolutions(m).borrow().values() {
+                let Some(did) =
+                    resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id())
+                else {
+                    continue;
+                };
+                if did.is_local() {
+                    // We don't record the doc alias name in the local crate
+                    // because the people who write doc alias are usually not
+                    // confused by them.
+                    continue;
+                }
+                if is_doc_alias_attrs_contain_symbol(r.tcx.get_attrs(did, sym::doc), item_name) {
+                    return Some(did);
+                }
+            }
+            None
+        };
+
+        if path.len() == 1 {
+            for rib in self.ribs[ns].iter().rev() {
+                let item = path[0].ident;
+                if let RibKind::Module(module) = rib.kind
+                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)
+                {
+                    return Some((did, item));
+                }
+            }
+        } else {
+            // Finds to the last resolved module item in the path
+            // and searches doc aliases within that module.
+            //
+            // Example: For the path `a::b::last_resolved::not_exist::c::d`,
+            // we will try to find any item has doc aliases named `not_exist`
+            // in `last_resolved` module.
+            //
+            // - Use `skip(1)` because the final segment must remain unresolved.
+            for (idx, seg) in path.iter().enumerate().rev().skip(1) {
+                let Some(id) = seg.id else {
+                    continue;
+                };
+                let Some(res) = self.r.partial_res_map.get(&id) else {
+                    continue;
+                };
+                if let Res::Def(DefKind::Mod, module) = res.expect_full_res()
+                    && let Some(module) = self.r.get_module(module)
+                    && let item = path[idx + 1].ident
+                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)
+                {
+                    return Some((did, item));
+                }
+                break;
+            }
+        }
+        None
+    }
+
     fn suggest_trait_and_bounds(
         &mut self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index c58f8480572..ee905065b96 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::{self as ast, Crate, NodeId, attr};
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::StabilityLevel;
+use rustc_attr_data_structures::StabilityLevel;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
 use rustc_expand::base::{
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index a32fe699016..01bb1324645 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
-use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, InnerSpan, Span, Symbol, sym};
 use thin_vec::ThinVec;
 use tracing::{debug, trace};
 
@@ -157,7 +157,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
     };
 
     for fragment in docs {
-        if fragment.doc == kw::Empty {
+        if fragment.doc == sym::empty {
             continue;
         }
 
@@ -177,7 +177,7 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
 ///
 /// Note: remove the trailing newline where appropriate
 pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
-    if frag.doc == kw::Empty {
+    if frag.doc == sym::empty {
         out.push('\n');
         return;
     }
@@ -514,20 +514,30 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
 /// This method does not always work, because markdown bytes don't necessarily match source bytes,
 /// like if escapes are used in the string. In this case, it returns `None`.
 ///
-/// This method will return `Some` only if:
+/// `markdown` is typically the entire documentation for an item,
+/// after combining fragments.
+///
+/// This method will return `Some` only if one of the following is true:
 ///
 /// - The doc is made entirely from sugared doc comments, which cannot contain escapes
-/// - The doc is entirely from a single doc fragment, with a string literal, exactly equal
+/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`.
 /// - The doc comes from `include_str!`
+/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment.
+///
+/// This function is defined in the compiler so it can be used by
+/// both `rustdoc` and `clippy`.
 pub fn source_span_for_markdown_range(
     tcx: TyCtxt<'_>,
     markdown: &str,
     md_range: &Range<usize>,
     fragments: &[DocFragment],
 ) -> Option<Span> {
+    use rustc_span::BytePos;
+
+    let map = tcx.sess.source_map();
     if let &[fragment] = &fragments
         && fragment.kind == DocFragmentKind::RawDoc
-        && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(fragment.span)
+        && let Ok(snippet) = map.span_to_snippet(fragment.span)
         && snippet.trim_end() == markdown.trim_end()
         && let Ok(md_range_lo) = u32::try_from(md_range.start)
         && let Ok(md_range_hi) = u32::try_from(md_range.end)
@@ -544,10 +554,43 @@ pub fn source_span_for_markdown_range(
     let is_all_sugared_doc = fragments.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
 
     if !is_all_sugared_doc {
+        // This case ignores the markdown outside of the range so that it can
+        // work in cases where the markdown is made from several different
+        // doc fragments, but the target range does not span across multiple
+        // fragments.
+        let mut match_data = None;
+        let pat = &markdown[md_range.clone()];
+        // This heirustic doesn't make sense with a zero-sized range.
+        if pat.is_empty() {
+            return None;
+        }
+        for (i, fragment) in fragments.iter().enumerate() {
+            if let Ok(snippet) = map.span_to_snippet(fragment.span)
+                && let Some(match_start) = snippet.find(pat)
+            {
+                // If there is either a match in a previous fragment, or
+                // multiple matches in this fragment, there is ambiguity.
+                if match_data.is_none() && !snippet[match_start + 1..].contains(pat) {
+                    match_data = Some((i, match_start));
+                } else {
+                    // Heirustic produced ambiguity, return nothing.
+                    return None;
+                }
+            }
+        }
+        if let Some((i, match_start)) = match_data {
+            let sp = fragments[i].span;
+            // we need to calculate the span start,
+            // then use that in our calulations for the span end
+            let lo = sp.lo() + BytePos(match_start as u32);
+            return Some(
+                sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
+            );
+        }
         return None;
     }
 
-    let snippet = tcx.sess.source_map().span_to_snippet(span_of_fragments(fragments)?).ok()?;
+    let snippet = map.span_to_snippet(span_of_fragments(fragments)?).ok()?;
 
     let starting_line = markdown[..md_range.start].matches('\n').count();
     let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count();
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 60e1b465ba9..144aeb5c369 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -195,6 +195,11 @@ pub struct CoverageOptions {
     /// regression tests for #133606, because we don't have an easy way to
     /// reproduce it from actual source code.
     pub discard_all_spans_in_codegen: bool,
+
+    /// `-Zcoverage-options=inject-unused-local-file`: During codegen, add an
+    /// extra dummy entry to each function's local file table, to exercise the
+    /// code that checks for local file IDs with no mapping regions.
+    pub inject_unused_local_file: bool,
 }
 
 /// Controls whether branch coverage or MC/DC coverage is enabled.
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 207ba5157bd..92f1bd8ab73 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -82,9 +82,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
                 let fname_ptr = info.dli_fname.as_ptr();
                 #[cfg(not(target_os = "cygwin"))]
                 let fname_ptr = {
-                    if info.dli_fname.is_null() {
-                        return Err("dladdr returned null pointer".into());
-                    }
+                    assert!(!info.dli_fname.is_null(), "dli_fname cannot be null");
                     info.dli_fname
                 };
                 let bytes = CStr::from_ptr(fname_ptr).to_bytes();
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 5b4068740a1..3d9fdcbc7b1 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1413,6 +1413,7 @@ pub mod parse {
                 "mcdc" => slot.level = CoverageLevel::Mcdc,
                 "no-mir-spans" => slot.no_mir_spans = true,
                 "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
+                "inject-unused-local-file" => slot.inject_unused_local_file = true,
                 _ => return false,
             }
         }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 010ae42c280..34ac37d6378 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -371,6 +371,11 @@ impl Session {
         self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
     }
 
+    /// True if testing flag `-Zcoverage-options=inject-unused-local-file` was passed.
+    pub fn coverage_inject_unused_local_file(&self) -> bool {
+        self.opts.unstable_opts.coverage_options.inject_unused_local_file
+    }
+
     pub fn is_sanitizer_cfi_enabled(&self) -> bool {
         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
     }
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index 6384fa06c21..c32593a6d95 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -29,7 +29,7 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec<RelativeBytePos>, Vec<Multi
     (lines, multi_byte_chars)
 }
 
-cfg_match! {
+cfg_select! {
     any(target_arch = "x86", target_arch = "x86_64") => {
         fn analyze_source_file_dispatch(
             src: &str,
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 22ca8accf9f..906462a0d22 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -20,7 +20,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(array_windows)]
-#![feature(cfg_match)]
+#![feature(cfg_select)]
 #![feature(core_io_borrowed_buf)]
 #![feature(hash_set_entry)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index efae6250b07..6b10d2728b2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -34,17 +34,8 @@ symbols! {
         // unnamed method parameters, crate root module, error recovery etc.
         // Matching predicates: `is_special`/`is_reserved`
         //
-        // Notes about `kw::Empty`:
-        // - Its use can blur the lines between "empty symbol" and "no symbol".
-        //   Using `Option<Symbol>` is preferable, where possible, because that
-        //   is unambiguous.
-        // - For dummy symbols that are never used and absolutely must be
-        //   present, it's better to use `sym::dummy` than `kw::Empty`, because
-        //   it's clearer that it's intended as a dummy value, and more likely
-        //   to be detected if it accidentally does get used.
         // tidy-alphabetical-start
         DollarCrate:        "$crate",
-        Empty:              "",
         PathRoot:           "{{root}}",
         Underscore:         "_",
         // tidy-alphabetical-end
@@ -398,7 +389,6 @@ symbols! {
         Wrapping,
         Yield,
         _DECLS,
-        _Self,
         __D,
         __H,
         __S,
@@ -864,7 +854,7 @@ symbols! {
         drop_types_in_const,
         dropck_eyepatch,
         dropck_parametricity,
-        dummy: "<!dummy!>", // use this instead of `kw::Empty` for symbols that won't be used
+        dummy: "<!dummy!>", // use this instead of `sym::empty` for symbols that won't be used
         dummy_cgu_name,
         dylib,
         dyn_compatible_for_dispatch,
@@ -883,6 +873,14 @@ symbols! {
         emit_enum_variant_arg,
         emit_struct,
         emit_struct_field,
+        // Notes about `sym::empty`:
+        // - It should only be used when it genuinely means "empty symbol". Use
+        //   `Option<Symbol>` when "no symbol" is a possibility.
+        // - For dummy symbols that are never used and absolutely must be
+        //   present, it's better to use `sym::dummy` than `sym::empty`, because
+        //   it's clearer that it's intended as a dummy value, and more likely
+        //   to be detected if it accidentally does get used.
+        empty: "",
         emscripten_wasm_eh,
         enable,
         encode,
@@ -2362,7 +2360,7 @@ impl Ident {
     #[inline]
     /// Constructs a new identifier from a symbol and a span.
     pub fn new(name: Symbol, span: Span) -> Ident {
-        debug_assert_ne!(name, kw::Empty);
+        debug_assert_ne!(name, sym::empty);
         Ident { name, span }
     }
 
@@ -2584,7 +2582,7 @@ impl Symbol {
     }
 
     pub fn is_empty(self) -> bool {
-        self == kw::Empty
+        self == sym::empty
     }
 
     /// This method is supposed to be used in error messages, so it's expected to be
@@ -2592,7 +2590,8 @@ impl Symbol {
     /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag
     /// or edition, so we have to guess the rawness using the global edition.
     pub fn to_ident_string(self) -> String {
-        Ident::with_dummy_span(self).to_string()
+        // Avoid creating an empty identifier, because that asserts in debug builds.
+        if self == sym::empty { String::new() } else { Ident::with_dummy_span(self).to_string() }
     }
 }
 
@@ -2772,7 +2771,7 @@ impl Symbol {
 
     /// Returns `true` if this symbol can be a raw identifier.
     pub fn can_be_raw(self) -> bool {
-        self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword()
+        self != sym::empty && self != kw::Underscore && !self.is_path_segment_keyword()
     }
 
     /// Was this symbol predefined in the compiler's `symbols!` macro
@@ -2822,7 +2821,7 @@ impl Ident {
     /// Whether this would be the identifier for a tuple field like `self.0`, as
     /// opposed to a named field like `self.thing`.
     pub fn is_numeric(self) -> bool {
-        !self.name.is_empty() && self.as_str().bytes().all(|b| b.is_ascii_digit())
+        self.as_str().bytes().all(|b| b.is_ascii_digit())
     }
 }
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 4a99ce09b39..644031af859 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::{
     self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
     TypeVisitable, TypeVisitableExt, UintTy,
 };
-use rustc_span::kw;
+use rustc_span::sym;
 
 pub(super) fn mangle<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -902,7 +902,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             print_prefix,
             ns,
             disambiguated_data.disambiguator as u64,
-            name.unwrap_or(kw::Empty).as_str(),
+            name.unwrap_or(sym::empty).as_str(),
         )
     }
 
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
index 87c07cd3109..4b75a6e5dbf 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -16,6 +16,10 @@ pub(crate) fn target() -> Target {
         arch: "aarch64".into(),
         options: TargetOptions {
             features: "+v8a,+outline-atomics".into(),
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             max_atomic_width: Some(128),
             stack_probes: StackProbeType::Inline,
             mcount: "\u{1}_mcount".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
index e785069c78a..2a16d1de3b5 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -1,6 +1,6 @@
 use rustc_abi::Endian;
 
-use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -20,6 +20,10 @@ pub(crate) fn target() -> Target {
         options: TargetOptions {
             abi: "ilp32".into(),
             features: "+v8a,+outline-atomics".into(),
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             stack_probes: StackProbeType::Inline,
             mcount: "\u{1}_mcount".into(),
             endian: Endian::Big,
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
index 41c25393e12..d8651f305fe 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs
@@ -1,4 +1,6 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{
+    FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
 // for target ABI requirements.
@@ -20,6 +22,10 @@ pub(crate) fn target() -> Target {
             // As documented in https://developer.android.com/ndk/guides/cpu-features.html
             // the neon (ASIMD) and FP must exist on all android aarch64 targets.
             features: "+v8a,+neon,+fp-armv8".into(),
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             stack_probes: StackProbeType::Inline,
             supported_sanitizers: SanitizerSet::CFI
                 | SanitizerSet::HWADDRESS
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
index c6be2c20ea2..4220d74dfc8 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{
+    FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -14,6 +16,10 @@ pub(crate) fn target() -> Target {
         arch: "aarch64".into(),
         options: TargetOptions {
             features: "+v8a,+outline-atomics".into(),
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             mcount: "\u{1}_mcount".into(),
             max_atomic_width: Some(128),
             stack_probes: StackProbeType::Inline,
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
index 166bb1ed215..a22c1289677 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{FramePointer, StackProbeType, Target, TargetMetadata, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -15,6 +15,10 @@ pub(crate) fn target() -> Target {
         options: TargetOptions {
             abi: "ilp32".into(),
             features: "+v8a,+outline-atomics".into(),
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             max_atomic_width: Some(128),
             stack_probes: StackProbeType::Inline,
             mcount: "\u{1}_mcount".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
index 58ba06e124c..58daaa03675 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs
@@ -1,4 +1,6 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{
+    FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_musl::opts();
@@ -26,6 +28,12 @@ pub(crate) fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
-        options: TargetOptions { mcount: "\u{1}_mcount".into(), ..base },
+        options: TargetOptions {
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
+             mcount: "\u{1}_mcount".into(), ..base
+         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
index f2994b1232e..51cdebf22db 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs
@@ -1,4 +1,6 @@
-use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base};
+use crate::spec::{
+    FramePointer, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_ohos::opts();
@@ -16,6 +18,10 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
         options: TargetOptions {
+            // the AAPCS64 expects use of non-leaf frame pointers per
+            // https://github.com/ARM-software/abi-aa/blob/4492d1570eb70c8fd146623e0db65b2d241f12e7/aapcs64/aapcs64.rst#the-frame-pointer
+            // and we tend to encounter interesting bugs in AArch64 unwinding code if we do not
+            frame_pointer: FramePointer::NonLeaf,
             mcount: "\u{1}_mcount".into(),
             stack_probes: StackProbeType::Inline,
             supported_sanitizers: SanitizerSet::ADDRESS
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 99b04ac2720..576c9bd6b57 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -980,14 +980,16 @@ impl Target {
                 // the use of soft-float, so all we can do here is some crude hacks.
                 match &*self.abi {
                     "softfloat" => {
-                        // This is not fully correct, LLVM actually doesn't let us enforce the softfloat
-                        // ABI properly... see <https://github.com/rust-lang/rust/issues/134375>.
-                        // FIXME: should we forbid "neon" here? But that would be a breaking change.
-                        NOTHING
+                        // LLVM will use float registers when `fp-armv8` is available, e.g. for
+                        // calls to built-ins. The only way to ensure a consistent softfloat ABI
+                        // on aarch64 is to never enable `fp-armv8`, so we enforce that.
+                        // In Rust we tie `neon` and `fp-armv8` together, therefore `neon` is the
+                        // feature we have to mark as incompatible.
+                        FeatureConstraints { required: &[], incompatible: &["neon"] }
                     }
                     _ => {
                         // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
-                        // These are Rust feature names and we use "neon" to control both of them.
+                        // `FeatureConstraints` uses Rust feature names, hence only "neon" shows up.
                         FeatureConstraints { required: &["neon"], incompatible: &[] }
                     }
                 }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 00922c6038e..9b949a0a795 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -337,6 +337,8 @@ trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected
     .label = unexpected quantity of predicates here
 trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause
     .label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}`
+trait_selection_rustc_on_unimplemented_invalid_name = invalid name in `on`-clause
+    .label = expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `{$invalid_name}`
 trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid
     .label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}`
 trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 970160ba212..b88040a0f98 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -841,16 +841,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 return None;
             };
 
-        let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
+        let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() {
             ty::Closure(def_id, args) => {
-                (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
+                (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false)
             }
             ty::CoroutineClosure(def_id, args) => (
                 def_id,
                 args.as_coroutine_closure()
                     .coroutine_closure_sig()
                     .map_bound(|sig| sig.tupled_inputs_ty),
-                Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
+                !args.as_coroutine_closure().tupled_upvars_ty().is_ty_var()
+                    && args.as_coroutine_closure().has_self_borrows(),
             ),
             _ => return None,
         };
@@ -884,10 +885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // If the closure has captures, then perhaps the reason that the trait
         // is unimplemented is because async closures don't implement `Fn`/`FnMut`
         // if they have captures.
-        if let Some(by_ref_captures) = by_ref_captures
-            && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
-            && !sig_tys.skip_binder().output().is_unit()
-        {
+        if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {
             let mut err = self.dcx().create_err(AsyncClosureNotFn {
                 span: self.tcx.def_span(closure_def_id),
                 kind: expected_kind.as_str(),
@@ -1503,11 +1501,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     return None;
                 };
 
-                let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self)
-                    .poly_select(&obligation.with(
-                        self.tcx,
-                        predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),
-                    ))
+                let trait_ref = self.enter_forall_and_leak_universe(
+                    predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),
+                );
+                let Ok(Some(ImplSource::UserDefined(impl_data))) =
+                    SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref))
                 else {
                     return None;
                 };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index d5ee6e2123a..37968386e9a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -429,7 +429,19 @@ impl<'tcx> OnUnimplementedDirective {
                 .next()
                 .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?;
 
-            match OnUnimplementedCondition::parse(cond) {
+            let generics: Vec<Symbol> = tcx
+                .generics_of(item_def_id)
+                .own_params
+                .iter()
+                .filter_map(|param| {
+                    if matches!(param.kind, GenericParamDefKind::Lifetime) {
+                        None
+                    } else {
+                        Some(param.name)
+                    }
+                })
+                .collect();
+            match OnUnimplementedCondition::parse(cond, &generics) {
                 Ok(condition) => Some(condition),
                 Err(e) => return Err(tcx.dcx().emit_err(e)),
             }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
index 13753761f09..e8ea9f2d23e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
@@ -26,9 +26,12 @@ impl OnUnimplementedCondition {
         })
     }
 
-    pub(crate) fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> {
+    pub(crate) fn parse(
+        input: &MetaItemInner,
+        generics: &[Symbol],
+    ) -> Result<Self, InvalidOnClause> {
         let span = input.span();
-        let pred = Predicate::parse(input)?;
+        let pred = Predicate::parse(input, generics)?;
         Ok(OnUnimplementedCondition { span, pred })
     }
 }
@@ -52,7 +55,7 @@ enum Predicate {
 }
 
 impl Predicate {
-    fn parse(input: &MetaItemInner) -> Result<Self, InvalidOnClause> {
+    fn parse(input: &MetaItemInner, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
         let meta_item = match input {
             MetaItemInner::MetaItem(meta_item) => meta_item,
             MetaItemInner::Lit(lit) => {
@@ -69,10 +72,10 @@ impl Predicate {
 
         match meta_item.kind {
             MetaItemKind::List(ref mis) => match predicate.name {
-                sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)),
-                sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)),
+                sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis, generics)?)),
+                sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis, generics)?)),
                 sym::not => match &**mis {
-                    [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))),
+                    [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one, generics)?))),
                     [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot {
                         span: first.span().to(last.span()),
                     }),
@@ -83,7 +86,7 @@ impl Predicate {
                 }
             },
             MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => {
-                let name = Name::parse(predicate);
+                let name = Name::parse(predicate, generics)?;
                 let value = FilterFormatString::parse(symbol);
                 let kv = NameValue { name, value };
                 Ok(Predicate::Match(kv))
@@ -95,8 +98,11 @@ impl Predicate {
         }
     }
 
-    fn parse_sequence(sequence: &[MetaItemInner]) -> Result<Vec<Self>, InvalidOnClause> {
-        sequence.iter().map(Predicate::parse).collect()
+    fn parse_sequence(
+        sequence: &[MetaItemInner],
+        generics: &[Symbol],
+    ) -> Result<Vec<Self>, InvalidOnClause> {
+        sequence.iter().map(|item| Predicate::parse(item, generics)).collect()
     }
 
     fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool {
@@ -156,14 +162,13 @@ enum Name {
 }
 
 impl Name {
-    fn parse(Ident { name, .. }: Ident) -> Self {
+    fn parse(Ident { name, span }: Ident, generics: &[Symbol]) -> Result<Self, InvalidOnClause> {
         match name {
-            sym::_Self | kw::SelfUpper => Name::SelfUpper,
-            sym::from_desugaring => Name::FromDesugaring,
-            sym::cause => Name::Cause,
-            // FIXME(mejrs) Perhaps we should start checking that
-            // this actually is a valid generic parameter?
-            generic => Name::GenericArg(generic),
+            kw::SelfUpper => Ok(Name::SelfUpper),
+            sym::from_desugaring => Ok(Name::FromDesugaring),
+            sym::cause => Ok(Name::Cause),
+            generic if generics.contains(&generic) => Ok(Name::GenericArg(generic)),
+            invalid_name => Err(InvalidOnClause::InvalidName { invalid_name, span }),
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
index ce170f820e1..7c1dfc1728f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
@@ -2,8 +2,8 @@ use std::fmt;
 use std::ops::Range;
 
 use errors::*;
-use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::TraitRefPrintSugared;
+use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{
     Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece,
     Position,
@@ -232,48 +232,16 @@ fn parse_arg<'tcx>(
 ) -> FormatArg {
     let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
     | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
-    let trait_name = tcx.item_ident(*trait_def_id);
-    let generics = tcx.generics_of(trait_def_id);
+
     let span = slice_span(input_span, arg.position_span.clone());
 
     match arg.position {
         // Something like "hello {name}"
         Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) {
-            // accepted, but deprecated
-            (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => {
-                warnings
-                    .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") });
-                FormatArg::SelfUpper
-            }
-            (
-                Ctx::RustcOnUnimplemented { .. },
-                sym::from_desugaring
-                | sym::crate_local
-                | sym::direct
-                | sym::cause
-                | sym::float
-                | sym::integer_
-                | sym::integral,
-            ) => {
-                warnings.push(FormatWarning::FutureIncompat {
-                    span,
-                    help: String::from("don't use this in a format string"),
-                });
-                FormatArg::AsIs(String::new())
-            }
-
             // Only `#[rustc_on_unimplemented]` can use these
             (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
             (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
             (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
-            // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}`
-            // because that'll be simpler to parse and extend in the future
-            (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => {
-                warnings
-                    .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") });
-                FormatArg::This
-            }
-
             // Any attribute can use these
             (
                 Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
@@ -282,7 +250,10 @@ fn parse_arg<'tcx>(
             (
                 Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
                 generic_param,
-            ) if generics.own_params.iter().any(|param| param.name == generic_param) => {
+            ) if tcx.generics_of(trait_def_id).own_params.iter().any(|param| {
+                !matches!(param.kind, GenericParamDefKind::Lifetime) && param.name == generic_param
+            }) =>
+            {
                 FormatArg::GenericParam { generic_param }
             }
 
@@ -375,39 +346,4 @@ pub mod errors {
     #[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
     #[help]
     pub struct MissingOptionsForOnUnimplementedAttr;
-
-    #[derive(LintDiagnostic)]
-    #[diag(trait_selection_ignored_diagnostic_option)]
-    pub struct IgnoredDiagnosticOption {
-        pub option_name: &'static str,
-        #[label]
-        pub span: Span,
-        #[label(trait_selection_other_label)]
-        pub prev_span: Span,
-    }
-
-    impl IgnoredDiagnosticOption {
-        pub fn maybe_emit_warning<'tcx>(
-            tcx: TyCtxt<'tcx>,
-            item_def_id: DefId,
-            new: Option<Span>,
-            old: Option<Span>,
-            option_name: &'static str,
-        ) {
-            if let (Some(new_item), Some(old_item)) = (new, old) {
-                if let Some(item_def_id) = item_def_id.as_local() {
-                    tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                        tcx.local_def_id_to_hir_id(item_def_id),
-                        new_item,
-                        IgnoredDiagnosticOption {
-                            span: new_item,
-                            prev_span: old_item,
-                            option_name,
-                        },
-                    );
-                }
-            }
-        }
-    }
 }
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 8801397b775..6863857f9ec 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2124,16 +2124,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         accessed through a specific `impl`",
                     self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
                 ));
-                err.span_suggestion(
-                    span,
-                    "use the fully qualified path to an implementation",
-                    format!(
-                        "<Type as {}>::{}",
-                        self.tcx.def_path_str(trait_ref),
-                        assoc_item.name()
-                    ),
-                    Applicability::HasPlaceholders,
-                );
+
+                if !assoc_item.is_impl_trait_in_trait() {
+                    err.span_suggestion(
+                        span,
+                        "use the fully qualified path to an implementation",
+                        format!(
+                            "<Type as {}>::{}",
+                            self.tcx.def_path_str(trait_ref),
+                            assoc_item.name()
+                        ),
+                        Applicability::HasPlaceholders,
+                    );
+                }
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 8ab4d795c45..779c861637a 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -72,6 +72,13 @@ pub enum InvalidOnClause {
         span: Span,
         invalid_flag: Symbol,
     },
+    #[diag(trait_selection_rustc_on_unimplemented_invalid_name, code = E0232)]
+    InvalidName {
+        #[primary_span]
+        #[label]
+        span: Span,
+        invalid_name: Symbol,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 3601c2cba9b..b68a7845366 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -1,19 +1,21 @@
 use std::ops::Deref;
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::LangItem;
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::{
-    Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
+    Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues,
 };
-use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
 use rustc_infer::traits::solve::Goal;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode};
+use rustc_next_trait_solver::solve::HasChanged;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 
-use crate::traits::{EvaluateConstErr, specialization_graph};
+use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph};
 
 #[repr(transparent)]
 pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -55,6 +57,52 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         (SolverDelegate(infcx), value, vars)
     }
 
+    fn compute_goal_fast_path(
+        &self,
+        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        span: Span,
+    ) -> Option<HasChanged> {
+        let pred = goal.predicate.kind();
+        match pred.no_bound_vars()? {
+            ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
+                Some(HasChanged::No)
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
+                self.0.sub_regions(
+                    SubregionOrigin::RelateRegionParamBound(span, None),
+                    outlives.1,
+                    outlives.0,
+                );
+                Some(HasChanged::No)
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
+                self.0.register_region_obligation_with_cause(
+                    outlives.0,
+                    outlives.1,
+                    &ObligationCause::dummy_with_span(span),
+                );
+
+                Some(HasChanged::No)
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
+                match self.0.tcx.as_lang_item(trait_pred.def_id()) {
+                    Some(LangItem::Sized)
+                        if trait_pred.self_ty().is_trivially_sized(self.0.tcx) =>
+                    {
+                        Some(HasChanged::No)
+                    }
+                    Some(LangItem::Copy | LangItem::Clone)
+                        if trait_pred.self_ty().is_trivially_pure_clone_copy() =>
+                    {
+                        Some(HasChanged::No)
+                    }
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
+
     fn fresh_var_for_kind_with_span(
         &self,
         arg: ty::GenericArg<'tcx>,
@@ -142,11 +190,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     fn instantiate_canonical_var_with_infer(
         &self,
-        cv_info: CanonicalVarInfo<'tcx>,
+        kind: CanonicalVarKind<'tcx>,
         span: Span,
         universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> ty::GenericArg<'tcx> {
-        self.0.instantiate_canonical_var(span, cv_info, universe_map)
+        self.0.instantiate_canonical_var(span, kind, universe_map)
     }
 
     fn add_item_bounds_for_hidden_type(
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 3e1cdac84df..aa3be43fcd1 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -12,6 +12,7 @@ use rustc_infer::traits::{
 use rustc_middle::ty::{
     self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
 };
+use rustc_next_trait_solver::delegate::SolverDelegate as _;
 use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
 use rustc_span::Span;
 use tracing::instrument;
@@ -172,7 +173,15 @@ where
                 }
 
                 let goal = obligation.as_goal();
-                let result = <&SolverDelegate<'tcx>>::from(infcx)
+                let delegate = <&SolverDelegate<'tcx>>::from(infcx);
+                if let Some(fast_path_has_changed) =
+                    delegate.compute_goal_fast_path(goal, obligation.cause.span)
+                {
+                    has_changed |= matches!(fast_path_has_changed, HasChanged::Yes);
+                    continue;
+                }
+
+                let result = delegate
                     .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
                     .0;
                 self.inspect_evaluated_obligation(infcx, &obligation, &result);
diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs
index 4fdaf740287..1f3168fafb1 100644
--- a/compiler/rustc_trait_selection/src/solve/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/select.rs
@@ -5,7 +5,7 @@ use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_infer::traits::{
     BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
-    PolyTraitObligation, Selection, SelectionError, SelectionResult,
+    Selection, SelectionError, SelectionResult, TraitObligation,
 };
 use rustc_macros::extension;
 use rustc_middle::{bug, span_bug};
@@ -17,7 +17,7 @@ use crate::solve::inspect::{self, ProofTreeInferCtxtExt};
 impl<'tcx> InferCtxt<'tcx> {
     fn select_in_new_trait_solver(
         &self,
-        obligation: &PolyTraitObligation<'tcx>,
+        obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
         assert!(self.next_trait_solver());
 
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 8d6e6b4a651..18f28d72f6f 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -188,6 +188,20 @@ where
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
+    /// Computes the least-upper-bound, or mutual supertype, of two values.
+    pub fn lub<T: ToTrace<'tcx>>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        expected: T,
+        actual: T,
+    ) -> Result<T, TypeError<'tcx>> {
+        self.infcx
+            .at(cause, param_env)
+            .lub(expected, actual)
+            .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+    }
+
     #[must_use]
     pub fn select_where_possible(&self) -> Vec<E> {
         self.engine.borrow_mut().select_where_possible(self.infcx)
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 31b075db04b..a9bdb909bdc 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -340,7 +340,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     let mut predicates: Vec<_> = util::elaborate(
         tcx,
         unnormalized_env.caller_bounds().into_iter().map(|predicate| {
-            if tcx.features().generic_const_exprs() {
+            if tcx.features().generic_const_exprs() || tcx.next_trait_solver_globally() {
                 return predicate;
             }
 
@@ -405,8 +405,6 @@ pub fn normalize_param_env_or_error<'tcx>(
             // compatibility. Eventually when lazy norm is implemented this can just be removed.
             // We do not normalize types here as there is no backwards compatibility requirement
             // for us to do so.
-            //
-            // FIXME(-Znext-solver): remove this hack since we have deferred projection equality
             predicate.fold_with(&mut ConstNormalizer(tcx))
         }),
     )
@@ -542,10 +540,13 @@ pub fn try_evaluate_const<'tcx>(
         | ty::ConstKind::Placeholder(_)
         | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
         ty::ConstKind::Unevaluated(uv) => {
+            let opt_anon_const_kind =
+                (tcx.def_kind(uv.def) == DefKind::AnonConst).then(|| tcx.anon_const_kind(uv.def));
+
             // Postpone evaluation of constants that depend on generic parameters or
             // inference variables.
             //
-            // We use `TypingMode::PostAnalysis`  here which is not *technically* correct
+            // We use `TypingMode::PostAnalysis` here which is not *technically* correct
             // to be revealing opaque types here as borrowcheck has not run yet. However,
             // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
             // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
@@ -553,65 +554,95 @@ pub fn try_evaluate_const<'tcx>(
             //
             // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
             // instead of having this logic here
-            let (args, typing_env) = if tcx.features().generic_const_exprs()
-                && uv.has_non_region_infer()
-            {
-                // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
-                // inference variables and generic parameters to show up in `ty::Const` even though the anon const
-                // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
-                match tcx.thir_abstract_const(uv.def) {
-                    Ok(Some(ct)) => {
-                        let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
-                        if let Err(e) = ct.error_reported() {
-                            return Err(EvaluateConstErr::EvaluationFailure(e));
-                        } else if ct.has_non_region_infer() || ct.has_non_region_param() {
-                            // If the anon const *does* actually use generic parameters or inference variables from
-                            // the generic arguments provided for it, then we should *not* attempt to evaluate it.
-                            return Err(EvaluateConstErr::HasGenericsOrInfers);
-                        } else {
-                            let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
-                            let typing_env = infcx
-                                .typing_env(tcx.erase_regions(param_env))
-                                .with_post_analysis_normalized(tcx);
-                            (args, typing_env)
+            let (args, typing_env) = match opt_anon_const_kind {
+                // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
+                // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
+                // about if you have to consider gce whatsoever.
+                Some(ty::AnonConstKind::GCE) => {
+                    if uv.has_non_region_infer() || uv.has_non_region_param() {
+                        // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
+                        // inference variables and generic parameters to show up in `ty::Const` even though the anon const
+                        // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
+                        match tcx.thir_abstract_const(uv.def) {
+                            Ok(Some(ct)) => {
+                                let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
+                                if let Err(e) = ct.error_reported() {
+                                    return Err(EvaluateConstErr::EvaluationFailure(e));
+                                } else if ct.has_non_region_infer() || ct.has_non_region_param() {
+                                    // If the anon const *does* actually use generic parameters or inference variables from
+                                    // the generic arguments provided for it, then we should *not* attempt to evaluate it.
+                                    return Err(EvaluateConstErr::HasGenericsOrInfers);
+                                } else {
+                                    let args =
+                                        replace_param_and_infer_args_with_placeholder(tcx, uv.args);
+                                    let typing_env = infcx
+                                        .typing_env(tcx.erase_regions(param_env))
+                                        .with_post_analysis_normalized(tcx);
+                                    (args, typing_env)
+                                }
+                            }
+                            Err(_) | Ok(None) => {
+                                let args = GenericArgs::identity_for_item(tcx, uv.def);
+                                let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
+                                (args, typing_env)
+                            }
                         }
+                    } else {
+                        let typing_env = infcx
+                            .typing_env(tcx.erase_regions(param_env))
+                            .with_post_analysis_normalized(tcx);
+                        (uv.args, typing_env)
                     }
-                    Err(_) | Ok(None) => {
-                        let args = GenericArgs::identity_for_item(tcx, uv.def);
-                        let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
-                        (args, typing_env)
+                }
+                Some(ty::AnonConstKind::RepeatExprCount) => {
+                    if uv.has_non_region_infer() {
+                        // Diagnostics will sometimes replace the identity args of anon consts in
+                        // array repeat expr counts with inference variables so we have to handle this
+                        // even though it is not something we should ever actually encounter.
+                        //
+                        // Array repeat expr counts are allowed to syntactically use generic parameters
+                        // but must not actually depend on them in order to evalaute successfully. This means
+                        // that it is actually fine to evalaute them in their own environment rather than with
+                        // the actually provided generic arguments.
+                        tcx.dcx().delayed_bug("AnonConst with infer args but no error reported");
                     }
+
+                    // The generic args of repeat expr counts under `min_const_generics` are not supposed to
+                    // affect evaluation of the constant as this would make it a "truly" generic const arg.
+                    // To prevent this we discard all the generic arguments and evalaute with identity args
+                    // and in its own environment instead of the current environment we are normalizing in.
+                    let args = GenericArgs::identity_for_item(tcx, uv.def);
+                    let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
+
+                    (args, typing_env)
+                }
+                _ => {
+                    // We are only dealing with "truly" generic/uninferred constants here:
+                    // - GCEConsts have been handled separately
+                    // - Repeat expr count back compat consts have also been handled separately
+                    // So we are free to simply defer evaluation here.
+                    //
+                    // FIXME: This assumes that `args` are normalized which is not necessarily true
+                    //
+                    // Const patterns are converted to type system constants before being
+                    // evaluated. However, we don't care about them here as pattern evaluation
+                    // logic does not go through type system normalization. If it did this would
+                    // be a backwards compatibility problem as we do not enforce "syntactic" non-
+                    // usage of generic parameters like we do here.
+                    if uv.args.has_non_region_param() || uv.args.has_non_region_infer() {
+                        return Err(EvaluateConstErr::HasGenericsOrInfers);
+                    }
+
+                    let typing_env = infcx
+                        .typing_env(tcx.erase_regions(param_env))
+                        .with_post_analysis_normalized(tcx);
+                    (uv.args, typing_env)
                 }
-            } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
-                // FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
-                //
-                // Diagnostics will sometimes replace the identity args of anon consts in
-                // array repeat expr counts with inference variables so we have to handle this
-                // even though it is not something we should ever actually encounter.
-                //
-                // Array repeat expr counts are allowed to syntactically use generic parameters
-                // but must not actually depend on them in order to evalaute successfully. This means
-                // that it is actually fine to evalaute them in their own environment rather than with
-                // the actually provided generic arguments.
-                tcx.dcx().delayed_bug(
-                    "Encountered anon const with inference variable args but no error reported",
-                );
-
-                let args = GenericArgs::identity_for_item(tcx, uv.def);
-                let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
-                (args, typing_env)
-            } else {
-                // FIXME: This codepath is reachable under `associated_const_equality` and in the
-                // future will be reachable by `min_generic_const_args`. We should handle inference
-                // variables and generic parameters properly instead of doing nothing.
-                let typing_env = infcx
-                    .typing_env(tcx.erase_regions(param_env))
-                    .with_post_analysis_normalized(tcx);
-                (uv.args, typing_env)
             };
-            let uv = ty::UnevaluatedConst::new(uv.def, args);
 
+            let uv = ty::UnevaluatedConst::new(uv.def, args);
             let erased_uv = tcx.erase_regions(uv);
+
             use rustc_middle::mir::interpret::ErrorHandled;
             match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
                 Ok(Ok(val)) => Ok(ty::Const::new_value(
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 88a0c402702..eb6d5c8a60a 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -299,12 +299,21 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
             );
         }
 
+        // We don't replace bound vars in the generic arguments of the free alias with
+        // placeholders. This doesn't cause any issues as instantiating parameters with
+        // bound variables is special-cased to rewrite the debruijn index to be higher
+        // whenever we fold through a binder.
+        //
+        // However, we do replace any escaping bound vars in the resulting goals with
+        // placeholders as the trait solver does not expect to encounter escaping bound
+        // vars in obligations.
+        //
+        // FIXME(lazy_type_alias): Check how much this actually matters for perf before
+        // stabilization. This is a bit weird and generally not how we handle binders in
+        // the compiler so ideally we'd do the same boundvar->placeholder->boundvar dance
+        // that other kinds of normalization do.
         let infcx = self.selcx.infcx;
         self.obligations.extend(
-            // FIXME(BoxyUwU):
-            // FIXME(lazy_type_alias):
-            // It seems suspicious to instantiate the predicates with arguments that might be bound vars,
-            // we might wind up instantiating one of these bound vars underneath a hrtb.
             infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
                 |(mut predicate, span)| {
                     if free.has_escaping_bound_vars() {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index ca58da5ca6d..ed0f34b5aa9 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -378,6 +378,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             term: projected_term,
             obligations: mut projected_obligations,
         })) => {
+            debug!("opt_normalize_projection_type: progress");
             // if projection succeeded, then what we get out of this
             // is also non-normalized (consider: it was derived from
             // an impl, where-clause etc) and hence we must
@@ -408,6 +409,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             Ok(Some(result.value))
         }
         Ok(Projected::NoProgress(projected_ty)) => {
+            debug!("opt_normalize_projection_type: no progress");
             let result =
                 Normalized { value: projected_ty, obligations: PredicateObligations::new() };
             infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
@@ -621,8 +623,17 @@ struct Progress<'tcx> {
 }
 
 impl<'tcx> Progress<'tcx> {
-    fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
-        Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() }
+    fn error_for_term(
+        tcx: TyCtxt<'tcx>,
+        alias_term: ty::AliasTerm<'tcx>,
+        guar: ErrorGuaranteed,
+    ) -> Self {
+        let err_term = if alias_term.kind(tcx).is_type() {
+            Ty::new_error(tcx, guar).into()
+        } else {
+            ty::Const::new_error(tcx, guar).into()
+        };
+        Progress { term: err_term, obligations: PredicateObligations::new() }
     }
 
     fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self {
@@ -650,7 +661,11 @@ fn project<'cx, 'tcx>(
     }
 
     if let Err(guar) = obligation.predicate.error_reported() {
-        return Ok(Projected::Progress(Progress::error(selcx.tcx(), guar)));
+        return Ok(Projected::Progress(Progress::error_for_term(
+            selcx.tcx(),
+            obligation.predicate,
+            guar,
+        )));
     }
 
     let mut candidates = ProjectionCandidateSet::None;
@@ -1965,7 +1980,13 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let param_env = obligation.param_env;
     let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
         Ok(assoc_term) => assoc_term,
-        Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
+        Err(guar) => {
+            return Ok(Projected::Progress(Progress::error_for_term(
+                tcx,
+                obligation.predicate,
+                guar,
+            )));
+        }
     };
 
     // This means that the impl is missing a definition for the
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 10a2ba049d8..7d869b27445 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -65,71 +65,92 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let def_id = obligation.predicate.def_id();
             let tcx = self.tcx();
 
-            if tcx.is_lang_item(def_id, LangItem::Copy) {
-                debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
-
-                // User-defined copy impls are permitted, but only for
-                // structs and enums.
-                self.assemble_candidates_from_impls(obligation, &mut candidates);
-
-                // For other types, we'll use the builtin rules.
-                let copy_conditions = self.copy_clone_conditions(obligation);
-                self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::DiscriminantKind) {
-                // `DiscriminantKind` is automatically implemented for every type.
-                candidates.vec.push(BuiltinCandidate { has_nested: false });
-            } else if tcx.is_lang_item(def_id, LangItem::PointeeTrait) {
-                // `Pointee` is automatically implemented for every type.
-                candidates.vec.push(BuiltinCandidate { has_nested: false });
-            } else if tcx.is_lang_item(def_id, LangItem::Sized) {
-                self.assemble_builtin_sized_candidate(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::Unsize) {
-                self.assemble_candidates_for_unsizing(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::Destruct) {
-                self.assemble_const_destruct_candidates(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::TransmuteTrait) {
-                // User-defined transmutability impls are permitted.
-                self.assemble_candidates_from_impls(obligation, &mut candidates);
-                self.assemble_candidates_for_transmutability(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::Tuple) {
-                self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
-                self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) {
-                self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
-                    obligation,
-                    &mut candidates,
-                );
-            } else {
-                if tcx.is_lang_item(def_id, LangItem::Clone) {
-                    // Same builtin conditions as `Copy`, i.e., every type which has builtin support
-                    // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
-                    // types have builtin support for `Clone`.
-                    let clone_conditions = self.copy_clone_conditions(obligation);
-                    self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+            let lang_item = tcx.as_lang_item(def_id);
+            match lang_item {
+                Some(LangItem::Copy | LangItem::Clone) => {
+                    debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+                    // User-defined copy impls are permitted, but only for
+                    // structs and enums.
+                    self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+                    // For other types, we'll use the builtin rules.
+                    let copy_conditions = self.copy_clone_conditions(obligation);
+                    self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
                 }
-
-                if tcx.is_lang_item(def_id, LangItem::Coroutine) {
-                    self.assemble_coroutine_candidates(obligation, &mut candidates);
-                } else if tcx.is_lang_item(def_id, LangItem::Future) {
-                    self.assemble_future_candidates(obligation, &mut candidates);
-                } else if tcx.is_lang_item(def_id, LangItem::Iterator) {
-                    self.assemble_iterator_candidates(obligation, &mut candidates);
-                } else if tcx.is_lang_item(def_id, LangItem::FusedIterator) {
-                    self.assemble_fused_iterator_candidates(obligation, &mut candidates);
-                } else if tcx.is_lang_item(def_id, LangItem::AsyncIterator) {
-                    self.assemble_async_iterator_candidates(obligation, &mut candidates);
-                } else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) {
-                    self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
+                Some(LangItem::DiscriminantKind) => {
+                    // `DiscriminantKind` is automatically implemented for every type.
+                    candidates.vec.push(BuiltinCandidate { has_nested: false });
                 }
+                Some(LangItem::PointeeTrait) => {
+                    // `Pointee` is automatically implemented for every type.
+                    candidates.vec.push(BuiltinCandidate { has_nested: false });
+                }
+                Some(LangItem::Sized) => {
+                    self.assemble_builtin_sized_candidate(obligation, &mut candidates);
+                }
+                Some(LangItem::Unsize) => {
+                    self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+                }
+                Some(LangItem::Destruct) => {
+                    self.assemble_const_destruct_candidates(obligation, &mut candidates);
+                }
+                Some(LangItem::TransmuteTrait) => {
+                    // User-defined transmutability impls are permitted.
+                    self.assemble_candidates_from_impls(obligation, &mut candidates);
+                    self.assemble_candidates_for_transmutability(obligation, &mut candidates);
+                }
+                Some(LangItem::Tuple) => {
+                    self.assemble_candidate_for_tuple(obligation, &mut candidates);
+                }
+                Some(LangItem::FnPtrTrait) => {
+                    self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
+                }
+                Some(LangItem::BikeshedGuaranteedNoDrop) => {
+                    self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
+                        obligation,
+                        &mut candidates,
+                    );
+                }
+                _ => {
+                    // We re-match here for traits that can have both builtin impls and user written impls.
+                    // After the builtin impls we need to also add user written impls, which we do not want to
+                    // do in general because just checking if there are any is expensive.
+                    match lang_item {
+                        Some(LangItem::Coroutine) => {
+                            self.assemble_coroutine_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::Future) => {
+                            self.assemble_future_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::Iterator) => {
+                            self.assemble_iterator_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::FusedIterator) => {
+                            self.assemble_fused_iterator_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::AsyncIterator) => {
+                            self.assemble_async_iterator_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::AsyncFnKindHelper) => {
+                            self.assemble_async_fn_kind_helper_candidates(
+                                obligation,
+                                &mut candidates,
+                            );
+                        }
+                        Some(LangItem::AsyncFn | LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => {
+                            self.assemble_async_closure_candidates(obligation, &mut candidates);
+                        }
+                        Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
+                            self.assemble_closure_candidates(obligation, &mut candidates);
+                            self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+                        }
+                        _ => {}
+                    }
 
-                // FIXME: Put these into `else if` blocks above, since they're built-in.
-                self.assemble_closure_candidates(obligation, &mut candidates);
-                self.assemble_async_closure_candidates(obligation, &mut candidates);
-                self.assemble_fn_pointer_candidates(obligation, &mut candidates);
-
-                self.assemble_candidates_from_impls(obligation, &mut candidates);
-                self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+                    self.assemble_candidates_from_impls(obligation, &mut candidates);
+                    self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+                }
             }
 
             self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
@@ -360,9 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        let Some(kind) = self.tcx().fn_trait_kind_from_def_id(obligation.predicate.def_id()) else {
-            return;
-        };
+        let kind = self.tcx().fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
 
         // Okay to skip binder because the args on closure types never
         // touch bound regions, they just capture the in-scope
@@ -424,11 +443,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        let Some(goal_kind) =
-            self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id())
-        else {
-            return;
-        };
+        let goal_kind =
+            self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
 
         match *obligation.self_ty().skip_binder().kind() {
             ty::CoroutineClosure(_, args) => {
@@ -501,11 +517,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        // We provide impl of all fn traits for fn pointers.
-        if !self.tcx().is_fn_trait(obligation.predicate.def_id()) {
-            return;
-        }
-
         // Keep this function in sync with extract_tupled_inputs_and_output_from_callable
         // until the old solver (and thus this function) is removed.
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 94190cd3ae3..c9169127e0b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -251,16 +251,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         let obligations = if has_nested {
             let trait_def = obligation.predicate.def_id();
-            let conditions = if tcx.is_lang_item(trait_def, LangItem::Sized) {
-                self.sized_conditions(obligation)
-            } else if tcx.is_lang_item(trait_def, LangItem::Copy) {
-                self.copy_clone_conditions(obligation)
-            } else if tcx.is_lang_item(trait_def, LangItem::Clone) {
-                self.copy_clone_conditions(obligation)
-            } else if tcx.is_lang_item(trait_def, LangItem::FusedIterator) {
-                self.fused_iterator_conditions(obligation)
-            } else {
-                bug!("unexpected builtin trait {:?}", trait_def)
+            let conditions = match tcx.as_lang_item(trait_def) {
+                Some(LangItem::Sized) => self.sized_conditions(obligation),
+                Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation),
+                Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation),
+                other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
             };
             let BuiltinImplConditions::Where(types) = conditions else {
                 bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 44a76f6e083..2be799735a8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -265,9 +265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        if self.infcx.next_trait_solver() {
-            return self.infcx.select_in_new_trait_solver(obligation);
-        }
+        assert!(!self.infcx.next_trait_solver());
 
         let candidate = match self.select_from_obligation(obligation) {
             Err(SelectionError::Overflow(OverflowError::Canonical)) => {
@@ -299,6 +297,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
+        if self.infcx.next_trait_solver() {
+            return self.infcx.select_in_new_trait_solver(obligation);
+        }
+
         self.poly_select(&Obligation {
             cause: obligation.cause.clone(),
             param_env: obligation.param_env,
@@ -2866,7 +2868,7 @@ fn rebind_coroutine_witness_types<'tcx>(
     let shifted_coroutine_types =
         tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder());
     ty::Binder::bind_with_vars(
-        ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args),
+        ty::EarlyBinder::bind(shifted_coroutine_types.types.to_vec()).instantiate(tcx, args),
         tcx.mk_bound_variable_kinds_from_iter(
             bound_vars.iter().chain(bound_coroutine_types.bound_vars()),
         ),
diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs
new file mode 100644
index 00000000000..447e13126cc
--- /dev/null
+++ b/compiler/rustc_traits/src/coroutine_witnesses.rs
@@ -0,0 +1,37 @@
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt, fold_regions};
+
+/// Return the set of types that should be taken into account when checking
+/// trait bounds on a coroutine's internal state. This properly replaces
+/// `ReErased` with new existential bound lifetimes.
+pub(crate) fn coroutine_hidden_types<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
+    let coroutine_layout = tcx.mir_coroutine_witnesses(def_id);
+    let mut vars = vec![];
+    let bound_tys = tcx.mk_type_list_from_iter(
+        coroutine_layout
+            .as_ref()
+            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
+            .filter(|decl| !decl.ignore_for_traits)
+            .map(|decl| {
+                let ty = fold_regions(tcx, decl.ty, |re, debruijn| {
+                    assert_eq!(re, tcx.lifetimes.re_erased);
+                    let var = ty::BoundVar::from_usize(vars.len());
+                    vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
+                    ty::Region::new_bound(
+                        tcx,
+                        debruijn,
+                        ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
+                    )
+                });
+                ty
+            }),
+    );
+
+    ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
+        ty::CoroutineWitnessTypes { types: bound_tys },
+        tcx.mk_bound_variable_kinds(&vars),
+    ))
+}
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 697c8391803..32d8c3f58e0 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -5,6 +5,7 @@
 // tidy-alphabetical-end
 
 mod codegen;
+mod coroutine_witnesses;
 mod dropck_outlives;
 mod evaluate_obligation;
 mod implied_outlives_bounds;
@@ -24,4 +25,5 @@ pub fn provide(p: &mut Providers) {
     normalize_erasing_regions::provide(p);
     type_op::provide(p);
     p.codegen_select_candidate = codegen::codegen_select_candidate;
+    p.coroutine_hidden_types = coroutine_witnesses::coroutine_hidden_types;
 }
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 67b67df4b28..2b1b0617cef 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -41,7 +41,7 @@ pub struct CanonicalQueryInput<I: Interner, V> {
 pub struct Canonical<I: Interner, V> {
     pub value: V,
     pub max_universe: UniverseIndex,
-    pub variables: I::CanonicalVars,
+    pub variables: I::CanonicalVarKinds,
 }
 
 impl<I: Interner, V> Canonical<I, V> {
@@ -89,63 +89,6 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
 #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
-#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
-#[cfg_attr(
-    feature = "nightly",
-    derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
-)]
-pub struct CanonicalVarInfo<I: Interner> {
-    pub kind: CanonicalVarKind<I>,
-}
-
-impl<I: Interner> CanonicalVarInfo<I> {
-    pub fn universe(self) -> UniverseIndex {
-        self.kind.universe()
-    }
-
-    #[must_use]
-    pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo<I> {
-        CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) }
-    }
-
-    pub fn is_existential(&self) -> bool {
-        match self.kind {
-            CanonicalVarKind::Ty(_) => true,
-            CanonicalVarKind::PlaceholderTy(_) => false,
-            CanonicalVarKind::Region(_) => true,
-            CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
-            CanonicalVarKind::PlaceholderConst(_) => false,
-        }
-    }
-
-    pub fn is_region(&self) -> bool {
-        match self.kind {
-            CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
-            CanonicalVarKind::Ty(_)
-            | CanonicalVarKind::PlaceholderTy(_)
-            | CanonicalVarKind::Const(_)
-            | CanonicalVarKind::PlaceholderConst(_) => false,
-        }
-    }
-
-    pub fn expect_placeholder_index(self) -> usize {
-        match self.kind {
-            CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
-                panic!("expected placeholder: {self:?}")
-            }
-
-            CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
-            CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
-            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
-        }
-    }
-}
-
-/// Describes the "kind" of the canonical variable. This is a "kind"
-/// in the type-theory sense of the term -- i.e., a "meta" type system
-/// that analyzes type-like values.
-#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
 #[cfg_attr(
     feature = "nightly",
     derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -214,6 +157,39 @@ impl<I: Interner> CanonicalVarKind<I> {
             }
         }
     }
+
+    pub fn is_existential(self) -> bool {
+        match self {
+            CanonicalVarKind::Ty(_) => true,
+            CanonicalVarKind::PlaceholderTy(_) => false,
+            CanonicalVarKind::Region(_) => true,
+            CanonicalVarKind::PlaceholderRegion(..) => false,
+            CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::PlaceholderConst(_) => false,
+        }
+    }
+
+    pub fn is_region(self) -> bool {
+        match self {
+            CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true,
+            CanonicalVarKind::Ty(_)
+            | CanonicalVarKind::PlaceholderTy(_)
+            | CanonicalVarKind::Const(_)
+            | CanonicalVarKind::PlaceholderConst(_) => false,
+        }
+    }
+
+    pub fn expect_placeholder_index(self) -> usize {
+        match self {
+            CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
+                panic!("expected placeholder: {self:?}")
+            }
+
+            CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
+            CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
+            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(),
+        }
+    }
 }
 
 /// Rust actually has more than one category of type variables;
@@ -306,11 +282,11 @@ impl<I: Interner> CanonicalVarValues<I> {
 
     // Given a list of canonical variables, construct a set of values which are
     // the identity response.
-    pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
+    pub fn make_identity(cx: I, infos: I::CanonicalVarKinds) -> CanonicalVarValues<I> {
         CanonicalVarValues {
             var_values: cx.mk_args_from_iter(infos.iter().enumerate().map(
-                |(i, info)| -> I::GenericArg {
-                    match info.kind {
+                |(i, kind)| -> I::GenericArg {
+                    match kind {
                         CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
                             Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
                                 .into()
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 0fd2d9f3ad3..7e88114df46 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -64,13 +64,16 @@ pub trait Interner:
         + TypeVisitable<Self>
         + SliceLike<Item = Self::LocalDefId>;
 
-    type CanonicalVars: Copy
+    type CanonicalVarKinds: Copy
         + Debug
         + Hash
         + Eq
-        + SliceLike<Item = ty::CanonicalVarInfo<Self>>
+        + SliceLike<Item = ty::CanonicalVarKind<Self>>
         + Default;
-    fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
+    fn mk_canonical_var_kinds(
+        self,
+        kinds: &[ty::CanonicalVarKind<Self>],
+    ) -> Self::CanonicalVarKinds;
 
     type ExternalConstraints: Copy
         + Debug
@@ -210,7 +213,7 @@ pub trait Interner:
     fn coroutine_hidden_types(
         self,
         def_id: Self::DefId,
-    ) -> ty::EarlyBinder<Self, ty::Binder<Self, Self::Tys>>;
+    ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::CoroutineWitnessTypes<Self>>>;
 
     fn fn_sig(
         self,
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index eae3213ead0..1b5d04e6025 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -193,7 +193,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
 
             ReVar(vid) => write!(f, "{vid:?}"),
 
-            RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
+            RePlaceholder(placeholder) => write!(f, "'{placeholder:?}"),
 
             // Use `'{erased}` as the output instead of `'erased` so that its more obviously distinct from
             // a `ReEarlyParam` named `'erased`. Technically that would print as `'erased/#IDX` so this is
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index cf2e4284d10..0cd98b5aa53 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1163,3 +1163,13 @@ pub struct FnHeader<I: Interner> {
     pub safety: I::Safety,
     pub abi: I::Abi,
 }
+
+#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)]
+#[cfg_attr(
+    feature = "nightly",
+    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct CoroutineWitnessTypes<I: Interner> {
+    pub types: I::Tys,
+}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 712f38a76c0..08b1828ff00 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1312,6 +1312,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// If [`make_contiguous`] was previously called, all elements of the
     /// deque will be in the first slice and the second slice will be empty.
+    /// Otherwise, the exact split point depends on implementation details
+    /// and is not guaranteed.
     ///
     /// [`make_contiguous`]: VecDeque::make_contiguous
     ///
@@ -1326,12 +1328,18 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// deque.push_back(1);
     /// deque.push_back(2);
     ///
-    /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..]));
+    /// let expected = [0, 1, 2];
+    /// let (front, back) = deque.as_slices();
+    /// assert_eq!(&expected[..front.len()], front);
+    /// assert_eq!(&expected[front.len()..], back);
     ///
     /// deque.push_front(10);
     /// deque.push_front(9);
     ///
-    /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
+    /// let expected = [9, 10, 0, 1, 2];
+    /// let (front, back) = deque.as_slices();
+    /// assert_eq!(&expected[..front.len()], front);
+    /// assert_eq!(&expected[front.len()..], back);
     /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
@@ -1347,6 +1355,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     ///
     /// If [`make_contiguous`] was previously called, all elements of the
     /// deque will be in the first slice and the second slice will be empty.
+    /// Otherwise, the exact split point depends on implementation details
+    /// and is not guaranteed.
     ///
     /// [`make_contiguous`]: VecDeque::make_contiguous
     ///
@@ -1363,9 +1373,22 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// deque.push_front(10);
     /// deque.push_front(9);
     ///
-    /// deque.as_mut_slices().0[0] = 42;
-    /// deque.as_mut_slices().1[0] = 24;
-    /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..]));
+    /// // Since the split point is not guaranteed, we may need to update
+    /// // either slice.
+    /// let mut update_nth = |index: usize, val: u32| {
+    ///     let (front, back) = deque.as_mut_slices();
+    ///     if index > front.len() - 1 {
+    ///         back[index - front.len()] = val;
+    ///     } else {
+    ///         front[index] = val;
+    ///     }
+    /// };
+    ///
+    /// update_nth(0, 42);
+    /// update_nth(2, 24);
+    ///
+    /// let v: Vec<_> = deque.into();
+    /// assert_eq!(v, [42, 10, 24, 1]);
     /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 7c5d22e1ee9..b49b3f41a76 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -69,7 +69,7 @@ use crate::boxed::Box;
 use crate::vec::Vec;
 
 impl<T> [T] {
-    /// Sorts the slice, preserving initial order of equal elements.
+    /// Sorts the slice in ascending order, preserving initial order of equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
@@ -137,7 +137,8 @@ impl<T> [T] {
         stable_sort(self, T::lt);
     }
 
-    /// Sorts the slice with a comparison function, preserving initial order of equal elements.
+    /// Sorts the slice in ascending order with a comparison function, preserving initial order of
+    /// equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*))
     /// worst-case.
@@ -197,7 +198,8 @@ impl<T> [T] {
         stable_sort(self, |a, b| compare(a, b) == Less);
     }
 
-    /// Sorts the slice with a key extraction function, preserving initial order of equal elements.
+    /// Sorts the slice in ascending order with a key extraction function, preserving initial order
+    /// of equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
@@ -252,7 +254,8 @@ impl<T> [T] {
         stable_sort(self, |a, b| f(a).lt(&f(b)));
     }
 
-    /// Sorts the slice with a key extraction function, preserving initial order of equal elements.
+    /// Sorts the slice in ascending order with a key extraction function, preserving initial order
+    /// of equal elements.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \*
     /// log(*n*)) worst-case, where the key function is *O*(*m*).
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 24c5d4c92f7..f1b1734b8b2 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -234,7 +234,7 @@ impl str {
     #[stable(feature = "str_box_extras", since = "1.20.0")]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
-    pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
+    pub fn into_boxed_bytes(self: Box<Self>) -> Box<[u8]> {
         self.into()
     }
 
@@ -320,6 +320,7 @@ impl str {
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[rustc_allow_incoherent_impl]
+    #[doc(alias = "replace_first")]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "str_replacen", since = "1.16.0")]
@@ -501,7 +502,7 @@ impl str {
     #[rustc_allow_incoherent_impl]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
-    pub fn into_string(self: Box<str>) -> String {
+    pub fn into_string(self: Box<Self>) -> String {
         let slice = Box::<[u8]>::from(self);
         unsafe { String::from_utf8_unchecked(slice.into_vec()) }
     }
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index c542a28beb8..d86dc24fb57 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -575,7 +575,7 @@ pub trait Into<T>: Sized {
 #[rustc_diagnostic_item = "From"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(on(
-    all(_Self = "&str", T = "alloc::string::String"),
+    all(Self = "&str", T = "alloc::string::String"),
     note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
 ))]
 #[doc(search_unbox)]
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 288d0df0d05..0bc98e2ea86 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -28,7 +28,7 @@ pub mod c_str;
     issue = "44930",
     reason = "the `c_variadic` feature has not been properly tested on all supported platforms"
 )]
-pub use self::va_list::{VaList, VaListImpl};
+pub use self::va_list::{VaArgSafe, VaList, VaListImpl};
 
 #[unstable(
     feature = "c_variadic",
diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs
index 351bf9f8314..fa23cf33af4 100644
--- a/library/core/src/ffi/primitives.rs
+++ b/library/core/src/ffi/primitives.rs
@@ -35,7 +35,7 @@ type_alias! { "c_float.md", c_float = f32; }
 type_alias! { "c_double.md", c_double = f64; }
 
 mod c_char_definition {
-    crate::cfg_match! {
+    crate::cfg_select! {
         // These are the targets on which c_char is unsigned. Usually the
         // signedness is the same for all target_os values on a given architecture
         // but there are some exceptions (see isSignedCharDefault() in clang).
@@ -133,7 +133,7 @@ mod c_char_definition {
 }
 
 mod c_long_definition {
-    crate::cfg_match! {
+    crate::cfg_select! {
         any(
             all(target_pointer_width = "64", not(windows)),
             // wasm32 Linux ABI uses 64-bit long
@@ -172,7 +172,7 @@ pub type c_ptrdiff_t = isize;
 pub type c_ssize_t = isize;
 
 mod c_int_definition {
-    crate::cfg_match! {
+    crate::cfg_select! {
         any(target_arch = "avr", target_arch = "msp430") => {
             pub(super) type c_int = i16;
             pub(super) type c_uint = u16;
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index 1ad8038cbf6..f12bd289f27 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -223,39 +223,57 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
     }
 }
 
-// The VaArgSafe trait needs to be used in public interfaces, however, the trait
-// itself must not be allowed to be used outside this module. Allowing users to
-// implement the trait for a new type (thereby allowing the va_arg intrinsic to
-// be used on a new type) is likely to cause undefined behavior.
-//
-// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
-// but also ensure it cannot be used elsewhere, the trait needs to be public
-// within a private module. Once RFC 2145 has been implemented look into
-// improving this.
-mod sealed_trait {
-    /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
-    pub unsafe trait VaArgSafe {}
-}
+mod sealed {
+    pub trait Sealed {}
 
-macro_rules! impl_va_arg_safe {
-    ($($t:ty),+) => {
-        $(
-            unsafe impl sealed_trait::VaArgSafe for $t {}
-        )+
-    }
+    impl Sealed for i32 {}
+    impl Sealed for i64 {}
+    impl Sealed for isize {}
+
+    impl Sealed for u32 {}
+    impl Sealed for u64 {}
+    impl Sealed for usize {}
+
+    impl Sealed for f64 {}
+
+    impl<T> Sealed for *mut T {}
+    impl<T> Sealed for *const T {}
 }
 
-impl_va_arg_safe! {i8, i16, i32, i64, usize}
-impl_va_arg_safe! {u8, u16, u32, u64, isize}
-impl_va_arg_safe! {f64}
+/// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
+///
+/// # Safety
+///
+/// This trait must only be implemented for types that C passes as varargs without implicit promotion.
+///
+/// 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.
+///
+/// [`c_int`]: core::ffi::c_int
+/// [`c_double`]: core::ffi::c_double
+pub unsafe trait VaArgSafe: sealed::Sealed {}
+
+// i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
+unsafe impl VaArgSafe for i32 {}
+unsafe impl VaArgSafe for i64 {}
+unsafe impl VaArgSafe for isize {}
+
+// u8 and u16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
+unsafe impl VaArgSafe for u32 {}
+unsafe impl VaArgSafe for u64 {}
+unsafe impl VaArgSafe for usize {}
+
+// f32 is implicitly promoted to c_double in C, and cannot implement `VaArgSafe`.
+unsafe impl VaArgSafe for f64 {}
 
-unsafe impl<T> sealed_trait::VaArgSafe for *mut T {}
-unsafe impl<T> sealed_trait::VaArgSafe for *const T {}
+unsafe impl<T> VaArgSafe for *mut T {}
+unsafe impl<T> VaArgSafe for *const T {}
 
 impl<'f> VaListImpl<'f> {
     /// Advance to the next arg.
     #[inline]
-    pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
+    pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
         // SAFETY: the caller must uphold the safety contract for `va_arg`.
         unsafe { va_arg(self) }
     }
@@ -317,4 +335,4 @@ unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
 /// argument `ap` points to.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-unsafe fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
+unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 4f7f8a5b84d..5978cb660f6 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -856,10 +856,10 @@ impl Display for Arguments<'_> {
     on(
         crate_local,
         label = "`{Self}` cannot be formatted using `{{:?}}`",
-        note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {Debug} for {Self}`"
+        note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`"
     ),
-    message = "`{Self}` doesn't implement `{Debug}`",
-    label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`"
+    message = "`{Self}` doesn't implement `{This}`",
+    label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`"
 )]
 #[doc(alias = "{:?}")]
 #[rustc_diagnostic_item = "Debug"]
@@ -969,12 +969,12 @@ pub use macros::Debug;
 /// ```
 #[rustc_on_unimplemented(
     on(
-        any(_Self = "std::path::Path", _Self = "std::path::PathBuf"),
+        any(Self = "std::path::Path", Self = "std::path::PathBuf"),
         label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it",
         note = "call `.display()` or `.to_string_lossy()` to safely print paths, \
                 as they may contain non-Unicode data"
     ),
-    message = "`{Self}` doesn't implement `{Display}`",
+    message = "`{Self}` doesn't implement `{This}`",
     label = "`{Self}` cannot be formatted with the default formatter",
     note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead"
 )]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 6eefb304689..8ea9de7e9e5 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -231,7 +231,7 @@ pub const unsafe fn assert_unchecked(cond: bool) {
 ///
 /// # Examples
 ///
-/// ```
+/// ```ignore-wasm
 /// use std::sync::atomic::{AtomicBool, Ordering};
 /// use std::sync::Arc;
 /// use std::{hint, thread};
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index effdc3c63ee..23bafa778bc 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -62,8 +62,7 @@
 #![allow(missing_docs)]
 
 use crate::marker::{DiscriminantKind, Tuple};
-use crate::mem::SizedTypeProperties;
-use crate::{ptr, ub_checks};
+use crate::ptr;
 
 pub mod fallback;
 pub mod mir;
@@ -3317,7 +3316,7 @@ pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
 /// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that
 /// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
 /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
-/// primarily used by [`ub_checks::assert_unsafe_precondition`].
+/// primarily used by [`crate::ub_checks::assert_unsafe_precondition`].
 #[rustc_intrinsic_const_stable_indirect] // just for UB checks
 #[inline(always)]
 #[rustc_intrinsic]
@@ -3595,306 +3594,38 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
 #[rustc_intrinsic]
 pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(ptr: *const P) -> M;
 
-// Some functions are defined here because they accidentally got made
-// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
-// (`transmute` also falls into this category, but it cannot be wrapped due to the
-// check that `T` and `U` have the same size.)
-
-/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-/// and destination must *not* overlap.
-///
-/// For regions of memory which might overlap, use [`copy`] instead.
-///
-/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
-/// with the source and destination arguments swapped,
-/// and `count` counting the number of `T`s instead of bytes.
-///
-/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
-/// requirements of `T`. The initialization state is preserved exactly.
-///
-/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-///
-/// * Both `src` and `dst` must be properly aligned.
-///
-/// * The region of memory beginning at `src` with a size of `count *
-///   size_of::<T>()` bytes must *not* overlap with the region of memory
-///   beginning at `dst` with the same size.
-///
-/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
-/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
-/// in the region beginning at `*src` and the region beginning at `*dst` can
-/// [violate memory safety][read-ownership].
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointers must be properly aligned.
-///
-/// [`read`]: crate::ptr::read
-/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Manually implement [`Vec::append`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-///     let src_len = src.len();
-///     let dst_len = dst.len();
-///
-///     // Ensure that `dst` has enough capacity to hold all of `src`.
-///     dst.reserve(src_len);
-///
-///     unsafe {
-///         // The call to add is always safe because `Vec` will never
-///         // allocate more than `isize::MAX` bytes.
-///         let dst_ptr = dst.as_mut_ptr().add(dst_len);
-///         let src_ptr = src.as_ptr();
-///
-///         // Truncate `src` without dropping its contents. We do this first,
-///         // to avoid problems in case something further down panics.
-///         src.set_len(0);
-///
-///         // The two regions cannot overlap because mutable references do
-///         // not alias, and two different vectors cannot own the same
-///         // memory.
-///         ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
-///
-///         // Notify `dst` that it now holds the contents of `src`.
-///         dst.set_len(dst_len + src_len);
-///     }
-/// }
-///
-/// let mut a = vec!['r'];
-/// let mut b = vec!['u', 's', 't'];
-///
-/// append(&mut a, &mut b);
-///
-/// assert_eq!(a, &['r', 'u', 's', 't']);
-/// assert!(b.is_empty());
-/// ```
-///
-/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
-#[doc(alias = "memcpy")]
+/// This is an accidentally-stable alias to [`ptr::copy_nonoverlapping`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::copy_nonoverlapping` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
 #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
-pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
-    #[rustc_intrinsic_const_stable_indirect]
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-
-    ub_checks::assert_unsafe_precondition!(
-        check_language_ub,
-        "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
-        and the specified memory ranges do not overlap",
-        (
-            src: *const () = src as *const (),
-            dst: *mut () = dst as *mut (),
-            size: usize = size_of::<T>(),
-            align: usize = align_of::<T>(),
-            count: usize = count,
-        ) => {
-            let zero_size = count == 0 || size == 0;
-            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
-                && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
-        }
-    );
-
-    // SAFETY: the safety contract for `copy_nonoverlapping` must be
-    // upheld by the caller.
-    unsafe { copy_nonoverlapping(src, dst, count) }
-}
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
-/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-/// and destination may overlap.
-///
-/// If the source and destination will *never* overlap,
-/// [`copy_nonoverlapping`] can be used instead.
-///
-/// `copy` is semantically equivalent to C's [`memmove`], but
-/// with the source and destination arguments swapped,
-/// and `count` counting the number of `T`s instead of bytes.
-/// Copying takes place as if the bytes were copied from `src`
-/// to a temporary array and then copied from the array to `dst`.
-///
-/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
-/// requirements of `T`. The initialization state is preserved exactly.
-///
-/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
-///   when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
-///   overlap, the `dst` pointer must not be invalidated by `src` reads.)
-///
-/// * Both `src` and `dst` must be properly aligned.
-///
-/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
-/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
-/// in the region beginning at `*src` and the region beginning at `*dst` can
-/// [violate memory safety][read-ownership].
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointers must be properly aligned.
-///
-/// [`read`]: crate::ptr::read
-/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Efficiently create a Rust vector from an unsafe buffer:
-///
-/// ```
-/// use std::ptr;
-///
-/// /// # Safety
-/// ///
-/// /// * `ptr` must be correctly aligned for its type and non-zero.
-/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
-/// /// * Those elements must not be used after calling this function unless `T: Copy`.
-/// # #[allow(dead_code)]
-/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
-///     let mut dst = Vec::with_capacity(elts);
-///
-///     // SAFETY: Our precondition ensures the source is aligned and valid,
-///     // and `Vec::with_capacity` ensures that we have usable space to write them.
-///     unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
-///
-///     // SAFETY: We created it with this much capacity earlier,
-///     // and the previous `copy` has initialized these elements.
-///     unsafe { dst.set_len(elts); }
-///     dst
-/// }
-/// ```
-#[doc(alias = "memmove")]
+/// This is an accidentally-stable alias to [`ptr::copy`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::copy` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
 #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_copy"]
-pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
-    #[rustc_intrinsic_const_stable_indirect]
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
-
-    // SAFETY: the safety contract for `copy` must be upheld by the caller.
-    unsafe {
-        ub_checks::assert_unsafe_precondition!(
-            check_language_ub,
-            "ptr::copy requires that both pointer arguments are aligned and non-null",
-            (
-                src: *const () = src as *const (),
-                dst: *mut () = dst as *mut (),
-                align: usize = align_of::<T>(),
-                zero_size: bool = T::IS_ZST || count == 0,
-            ) =>
-            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
-                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
-        );
-        copy(src, dst, count)
-    }
-}
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
-/// `val`.
-///
-/// `write_bytes` is similar to C's [`memset`], but sets `count *
-/// size_of::<T>()` bytes to `val`.
-///
-/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be properly aligned.
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointer must be properly aligned.
-///
-/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
-/// later if the written bytes are not a valid representation of some `T`. For instance, the
-/// following is an **incorrect** use of this function:
-///
-/// ```rust,no_run
-/// unsafe {
-///     let mut value: u8 = 0;
-///     let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
-///     let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
-///     ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
-///     let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
-/// }
-/// ```
-///
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut vec = vec![0u32; 4];
-/// unsafe {
-///     let vec_ptr = vec.as_mut_ptr();
-///     ptr::write_bytes(vec_ptr, 0xfe, 2);
-/// }
-/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
-/// ```
-#[doc(alias = "memset")]
+/// This is an accidentally-stable alias to [`ptr::write_bytes`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::write_bytes` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
-#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_write_bytes"]
-pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
-    #[rustc_intrinsic_const_stable_indirect]
-    #[rustc_nounwind]
-    #[rustc_intrinsic]
-    const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-
-    // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
-    unsafe {
-        ub_checks::assert_unsafe_precondition!(
-            check_language_ub,
-            "ptr::write_bytes requires that the destination pointer is aligned and non-null",
-            (
-                addr: *const () = dst as *const (),
-                align: usize = align_of::<T>(),
-                zero_size: bool = T::IS_ZST || count == 0,
-            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
-        );
-        write_bytes(dst, val, count)
-    }
-}
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
 /// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
 ///
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 97bb21c8a36..3bc9cff8072 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -97,32 +97,32 @@ use super::TrustedLen;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        _Self = "&[{A}]",
+        Self = "&[{A}]",
         message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
     on(
-        all(A = "{integer}", any(_Self = "&[{integral}]",)),
+        all(A = "{integer}", any(Self = "&[{integral}]",)),
         message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
     on(
-        _Self = "[{A}]",
+        Self = "[{A}]",
         message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
     on(
-        all(A = "{integer}", any(_Self = "[{integral}]",)),
+        all(A = "{integer}", any(Self = "[{integral}]",)),
         message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size",
         label = "try explicitly collecting into a `Vec<{A}>`",
     ),
     on(
-        _Self = "[{A}; _]",
+        Self = "[{A}; _]",
         message = "an array of type `{Self}` cannot be built directly from an iterator",
         label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
     ),
     on(
-        all(A = "{integer}", any(_Self = "[{integral}; _]",)),
+        all(A = "{integer}", any(Self = "[{integral}; _]",)),
         message = "an array of type `{Self}` cannot be built directly from an iterator",
         label = "try collecting into a `Vec<{A}>`, then using `.try_into()`",
     ),
@@ -239,41 +239,38 @@ pub trait FromIterator<A>: Sized {
 #[rustc_diagnostic_item = "IntoIterator"]
 #[rustc_on_unimplemented(
     on(
-        _Self = "core::ops::range::RangeTo<Idx>",
+        Self = "core::ops::range::RangeTo<Idx>",
         label = "if you meant to iterate until a value, add a starting value",
         note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
               bounded `Range`: `0..end`"
     ),
     on(
-        _Self = "core::ops::range::RangeToInclusive<Idx>",
+        Self = "core::ops::range::RangeToInclusive<Idx>",
         label = "if you meant to iterate until a value (including it), add a starting value",
         note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
               to have a bounded `RangeInclusive`: `0..=end`"
     ),
     on(
-        _Self = "[]",
+        Self = "[]",
         label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
     ),
-    on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
+    on(Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
     on(
-        _Self = "alloc::vec::Vec<T, A>",
+        Self = "alloc::vec::Vec<T, A>",
         label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
     ),
+    on(Self = "&str", label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"),
     on(
-        _Self = "&str",
+        Self = "alloc::string::String",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
-        _Self = "alloc::string::String",
-        label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
-    ),
-    on(
-        _Self = "{integral}",
+        Self = "{integral}",
         note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
               syntax `start..end` or the inclusive range syntax `start..=end`"
     ),
     on(
-        _Self = "{float}",
+        Self = "{float}",
         note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
               syntax `start..end` or the inclusive range syntax `start..=end`"
     ),
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index d1e71f0e60f..cf85bdb1352 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -22,11 +22,11 @@ fn _assert_is_dyn_compatible(_: &dyn Iterator<Item = ()>) {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        _Self = "core::ops::range::RangeTo<Idx>",
+        Self = "core::ops::range::RangeTo<Idx>",
         note = "you might have meant to use a bounded `Range`"
     ),
     on(
-        _Self = "core::ops::range::RangeToInclusive<Idx>",
+        Self = "core::ops::range::RangeToInclusive<Idx>",
         note = "you might have meant to use a bounded `RangeInclusive`"
     ),
     label = "`{Self}` is not an iterator",
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index e605d7e0d78..c49513f7a6d 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -100,7 +100,7 @@
 #![feature(bigint_helper_methods)]
 #![feature(bstr)]
 #![feature(bstr_internals)]
-#![feature(cfg_match)]
+#![feature(cfg_select)]
 #![feature(cfg_target_has_reliable_f16_f128)]
 #![feature(const_carrying_mul_add)]
 #![feature(const_eval_select)]
@@ -158,7 +158,6 @@
 #![feature(intra_doc_pointers)]
 #![feature(intrinsics)]
 #![feature(lang_items)]
-#![feature(let_chains)]
 #![feature(link_llvm_intrinsics)]
 #![feature(macro_metavar_expr)]
 #![feature(marker_trait_attr)]
@@ -235,8 +234,8 @@ pub mod autodiff {
 #[unstable(feature = "contracts", issue = "128044")]
 pub mod contracts;
 
-#[unstable(feature = "cfg_match", issue = "115585")]
-pub use crate::macros::cfg_match;
+#[unstable(feature = "cfg_select", issue = "115585")]
+pub use crate::macros::cfg_select;
 
 #[macro_use]
 mod internal_macros;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 7dc8c060cd5..4742add0957 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -210,9 +210,9 @@ pub macro assert_matches {
 /// # Example
 ///
 /// ```
-/// #![feature(cfg_match)]
+/// #![feature(cfg_select)]
 ///
-/// cfg_match! {
+/// cfg_select! {
 ///     unix => {
 ///         fn foo() { /* unix specific functionality */ }
 ///     }
@@ -228,19 +228,19 @@ pub macro assert_matches {
 /// If desired, it is possible to return expressions through the use of surrounding braces:
 ///
 /// ```
-/// #![feature(cfg_match)]
+/// #![feature(cfg_select)]
 ///
-/// let _some_string = cfg_match! {{
+/// let _some_string = cfg_select! {{
 ///     unix => { "With great power comes great electricity bills" }
 ///     _ => { "Behind every successful diet is an unwatched pizza" }
 /// }};
 /// ```
-#[unstable(feature = "cfg_match", issue = "115585")]
-#[rustc_diagnostic_item = "cfg_match"]
+#[unstable(feature = "cfg_select", issue = "115585")]
+#[rustc_diagnostic_item = "cfg_select"]
 #[rustc_macro_transparency = "semitransparent"]
-pub macro cfg_match {
+pub macro cfg_select {
     ({ $($tt:tt)* }) => {{
-        $crate::cfg_match! { $($tt)* }
+        $crate::cfg_select! { $($tt)* }
     }},
     (_ => { $($output:tt)* }) => {
         $($output)*
@@ -250,10 +250,10 @@ pub macro cfg_match {
         $($( $rest:tt )+)?
     ) => {
         #[cfg($cfg)]
-        $crate::cfg_match! { _ => $output }
+        $crate::cfg_select! { _ => $output }
         $(
             #[cfg(not($cfg))]
-            $crate::cfg_match! { $($rest)+ }
+            $crate::cfg_select! { $($rest)+ }
         )?
     },
 }
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index f33b8d188d8..700fb0f386e 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -550,72 +550,72 @@ pub trait BikeshedGuaranteedNoDrop {}
 #[lang = "sync"]
 #[rustc_on_unimplemented(
     on(
-        _Self = "core::cell::once::OnceCell<T>",
+        Self = "core::cell::once::OnceCell<T>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
     ),
     on(
-        _Self = "core::cell::Cell<u8>",
+        Self = "core::cell::Cell<u8>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
     ),
     on(
-        _Self = "core::cell::Cell<u16>",
+        Self = "core::cell::Cell<u16>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
     ),
     on(
-        _Self = "core::cell::Cell<u32>",
+        Self = "core::cell::Cell<u32>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
     ),
     on(
-        _Self = "core::cell::Cell<u64>",
+        Self = "core::cell::Cell<u64>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
     ),
     on(
-        _Self = "core::cell::Cell<usize>",
+        Self = "core::cell::Cell<usize>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
     ),
     on(
-        _Self = "core::cell::Cell<i8>",
+        Self = "core::cell::Cell<i8>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
     ),
     on(
-        _Self = "core::cell::Cell<i16>",
+        Self = "core::cell::Cell<i16>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
     ),
     on(
-        _Self = "core::cell::Cell<i32>",
+        Self = "core::cell::Cell<i32>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
     ),
     on(
-        _Self = "core::cell::Cell<i64>",
+        Self = "core::cell::Cell<i64>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
     ),
     on(
-        _Self = "core::cell::Cell<isize>",
+        Self = "core::cell::Cell<isize>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
     ),
     on(
-        _Self = "core::cell::Cell<bool>",
+        Self = "core::cell::Cell<bool>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
     ),
     on(
         all(
-            _Self = "core::cell::Cell<T>",
-            not(_Self = "core::cell::Cell<u8>"),
-            not(_Self = "core::cell::Cell<u16>"),
-            not(_Self = "core::cell::Cell<u32>"),
-            not(_Self = "core::cell::Cell<u64>"),
-            not(_Self = "core::cell::Cell<usize>"),
-            not(_Self = "core::cell::Cell<i8>"),
-            not(_Self = "core::cell::Cell<i16>"),
-            not(_Self = "core::cell::Cell<i32>"),
-            not(_Self = "core::cell::Cell<i64>"),
-            not(_Self = "core::cell::Cell<isize>"),
-            not(_Self = "core::cell::Cell<bool>")
+            Self = "core::cell::Cell<T>",
+            not(Self = "core::cell::Cell<u8>"),
+            not(Self = "core::cell::Cell<u16>"),
+            not(Self = "core::cell::Cell<u32>"),
+            not(Self = "core::cell::Cell<u64>"),
+            not(Self = "core::cell::Cell<usize>"),
+            not(Self = "core::cell::Cell<i8>"),
+            not(Self = "core::cell::Cell<i16>"),
+            not(Self = "core::cell::Cell<i32>"),
+            not(Self = "core::cell::Cell<i64>"),
+            not(Self = "core::cell::Cell<isize>"),
+            not(Self = "core::cell::Cell<bool>")
         ),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
     ),
     on(
-        _Self = "core::cell::RefCell<T>",
+        Self = "core::cell::RefCell<T>",
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
     ),
     message = "`{Self}` cannot be shared between threads safely",
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 27387754633..0a5f3ee35b1 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -21,6 +21,8 @@ mod transmutability;
 #[unstable(feature = "transmutability", issue = "99571")]
 pub use transmutability::{Assume, TransmuteFrom};
 
+// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do
+// the special magic "types have equal size" check at the call site.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(inline)]
 pub use crate::intrinsics::transmute;
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 9525bdb6762..bf67b6ed05a 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -12,9 +12,9 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::convert::FloatToInt;
-use crate::num::{FpCategory, libm};
+use crate::num::FpCategory;
 use crate::panic::const_assert;
-use crate::{cfg_match, intrinsics, mem};
+use crate::{cfg_select, intrinsics, mem};
 
 /// The radix or base of the internal representation of `f32`.
 /// Use [`f32::RADIX`] instead.
@@ -990,7 +990,7 @@ impl f32 {
     #[stable(feature = "num_midpoint", since = "1.85.0")]
     #[rustc_const_stable(feature = "num_midpoint", since = "1.85.0")]
     pub const fn midpoint(self, other: f32) -> f32 {
-        cfg_match! {
+        cfg_select! {
             // Allow faster implementation that have known good 64-bit float
             // implementations. Falling back to the branchy code on targets that don't
             // have 64-bit hardware floats or buggy implementations.
@@ -1557,413 +1557,441 @@ impl f32 {
     }
 }
 
-/// Experimental version of `floor` in `core`. See [`f32::floor`] for details.
+/// Experimental implementations of floating point functions in `core`.
 ///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let f = 3.7_f32;
-/// let g = 3.0_f32;
-/// let h = -3.7_f32;
-///
-/// assert_eq!(f32::floor(f), 3.0);
-/// assert_eq!(f32::floor(g), 3.0);
-/// assert_eq!(f32::floor(h), -4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::floor`]: ../../std/primitive.f32.html#method.floor
-#[inline]
+/// _The standalone functions in this module are for testing only.
+/// They will be stabilized as inherent methods._
 #[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn floor(x: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::floorf32(x) }
-}
+pub mod math {
+    use crate::intrinsics;
+    use crate::num::libm;
 
-/// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let f = 3.01_f32;
-/// let g = 4.0_f32;
-///
-/// assert_eq!(f32::ceil(f), 4.0);
-/// assert_eq!(f32::ceil(g), 4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::ceil`]: ../../std/primitive.f32.html#method.ceil
-#[inline]
-#[doc(alias = "ceiling")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-#[unstable(feature = "core_float_math", issue = "137578")]
-pub fn ceil(x: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::ceilf32(x) }
-}
+    /// Experimental version of `floor` in `core`. See [`f32::floor`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let f = 3.7_f32;
+    /// let g = 3.0_f32;
+    /// let h = -3.7_f32;
+    ///
+    /// assert_eq!(f32::math::floor(f), 3.0);
+    /// assert_eq!(f32::math::floor(g), 3.0);
+    /// assert_eq!(f32::math::floor(h), -4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::floor`]: ../../../std/primitive.f32.html#method.floor
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn floor(x: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::floorf32(x) }
+    }
 
-/// Experimental version of `round` in `core`. See [`f32::round`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let f = 3.3_f32;
-/// let g = -3.3_f32;
-/// let h = -3.7_f32;
-/// let i = 3.5_f32;
-/// let j = 4.5_f32;
-///
-/// assert_eq!(f32::round(f), 3.0);
-/// assert_eq!(f32::round(g), -3.0);
-/// assert_eq!(f32::round(h), -4.0);
-/// assert_eq!(f32::round(i), 4.0);
-/// assert_eq!(f32::round(j), 5.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::round`]: ../../std/primitive.f32.html#method.round
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn round(x: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::roundf32(x) }
-}
+    /// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let f = 3.01_f32;
+    /// let g = 4.0_f32;
+    ///
+    /// assert_eq!(f32::math::ceil(f), 4.0);
+    /// assert_eq!(f32::math::ceil(g), 4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::ceil`]: ../../../std/primitive.f32.html#method.ceil
+    #[inline]
+    #[doc(alias = "ceiling")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    pub fn ceil(x: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::ceilf32(x) }
+    }
 
-/// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let f = 3.3_f32;
-/// let g = -3.3_f32;
-/// let h = 3.5_f32;
-/// let i = 4.5_f32;
-///
-/// assert_eq!(f32::round_ties_even(f), 3.0);
-/// assert_eq!(f32::round_ties_even(g), -3.0);
-/// assert_eq!(f32::round_ties_even(h), 4.0);
-/// assert_eq!(f32::round_ties_even(i), 4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::round_ties_even`]: ../../std/primitive.f32.html#method.round_ties_even
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn round_ties_even(x: f32) -> f32 {
-    intrinsics::round_ties_even_f32(x)
-}
+    /// Experimental version of `round` in `core`. See [`f32::round`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let f = 3.3_f32;
+    /// let g = -3.3_f32;
+    /// let h = -3.7_f32;
+    /// let i = 3.5_f32;
+    /// let j = 4.5_f32;
+    ///
+    /// assert_eq!(f32::math::round(f), 3.0);
+    /// assert_eq!(f32::math::round(g), -3.0);
+    /// assert_eq!(f32::math::round(h), -4.0);
+    /// assert_eq!(f32::math::round(i), 4.0);
+    /// assert_eq!(f32::math::round(j), 5.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::round`]: ../../../std/primitive.f32.html#method.round
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round(x: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::roundf32(x) }
+    }
 
-/// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let f = 3.7_f32;
-/// let g = 3.0_f32;
-/// let h = -3.7_f32;
-///
-/// assert_eq!(f32::trunc(f), 3.0);
-/// assert_eq!(f32::trunc(g), 3.0);
-/// assert_eq!(f32::trunc(h), -3.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::trunc`]: ../../std/primitive.f32.html#method.trunc
-#[inline]
-#[doc(alias = "truncate")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-#[unstable(feature = "core_float_math", issue = "137578")]
-pub fn trunc(x: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::truncf32(x) }
-}
+    /// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for
+    /// details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let f = 3.3_f32;
+    /// let g = -3.3_f32;
+    /// let h = 3.5_f32;
+    /// let i = 4.5_f32;
+    ///
+    /// assert_eq!(f32::math::round_ties_even(f), 3.0);
+    /// assert_eq!(f32::math::round_ties_even(g), -3.0);
+    /// assert_eq!(f32::math::round_ties_even(h), 4.0);
+    /// assert_eq!(f32::math::round_ties_even(i), 4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::round_ties_even`]: ../../../std/primitive.f32.html#method.round_ties_even
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round_ties_even(x: f32) -> f32 {
+        intrinsics::round_ties_even_f32(x)
+    }
 
-/// Experimental version of `fract` in `core`. See [`f32::fract`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let x = 3.6_f32;
-/// let y = -3.6_f32;
-/// let abs_difference_x = (f32::fract(x) - 0.6).abs();
-/// let abs_difference_y = (f32::fract(y) - (-0.6)).abs();
-///
-/// assert!(abs_difference_x <= f32::EPSILON);
-/// assert!(abs_difference_y <= f32::EPSILON);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::fract`]: ../../std/primitive.f32.html#method.fract
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn fract(x: f32) -> f32 {
-    x - trunc(x)
-}
+    /// Experimental version of `trunc` in `core`. See [`f32::trunc`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let f = 3.7_f32;
+    /// let g = 3.0_f32;
+    /// let h = -3.7_f32;
+    ///
+    /// assert_eq!(f32::math::trunc(f), 3.0);
+    /// assert_eq!(f32::math::trunc(g), 3.0);
+    /// assert_eq!(f32::math::trunc(h), -3.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::trunc`]: ../../../std/primitive.f32.html#method.trunc
+    #[inline]
+    #[doc(alias = "truncate")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    pub fn trunc(x: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::truncf32(x) }
+    }
 
-/// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
-/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] {
-/// use core::f32;
-///
-/// let m = 10.0_f32;
-/// let x = 4.0_f32;
-/// let b = 60.0_f32;
-///
-/// assert_eq!(f32::mul_add(m, x, b), 100.0);
-/// assert_eq!(m * x + b, 100.0);
-///
-/// let one_plus_eps = 1.0_f32 + f32::EPSILON;
-/// let one_minus_eps = 1.0_f32 - f32::EPSILON;
-/// let minus_one = -1.0_f32;
-///
-/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
-/// assert_eq!(f32::mul_add(one_plus_eps, one_minus_eps, minus_one), -f32::EPSILON * f32::EPSILON);
-/// // Different rounding with the non-fused multiply and add.
-/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
-/// # }
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::mul_add`]: ../../std/primitive.f32.html#method.mul_add
-#[inline]
-#[doc(alias = "fmaf", alias = "fusedMultiplyAdd")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-#[unstable(feature = "core_float_math", issue = "137578")]
-pub fn mul_add(x: f32, y: f32, z: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::fmaf32(x, y, z) }
-}
+    /// Experimental version of `fract` in `core`. See [`f32::fract`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let x = 3.6_f32;
+    /// let y = -3.6_f32;
+    /// let abs_difference_x = (f32::math::fract(x) - 0.6).abs();
+    /// let abs_difference_y = (f32::math::fract(y) - (-0.6)).abs();
+    ///
+    /// assert!(abs_difference_x <= f32::EPSILON);
+    /// assert!(abs_difference_y <= f32::EPSILON);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::fract`]: ../../../std/primitive.f32.html#method.fract
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn fract(x: f32) -> f32 {
+        x - trunc(x)
+    }
 
-/// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let a: f32 = 7.0;
-/// let b = 4.0;
-/// assert_eq!(f32::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0
-/// assert_eq!(f32::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0
-/// assert_eq!(f32::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0
-/// assert_eq!(f32::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::div_euclid`]: ../../std/primitive.f32.html#method.div_euclid
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn div_euclid(x: f32, rhs: f32) -> f32 {
-    let q = trunc(x / rhs);
-    if x % rhs < 0.0 {
-        return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+    /// Experimental version of `mul_add` in `core`. See [`f32::mul_add`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// # // FIXME(#140515): mingw has an incorrect fma
+    /// # // https://sourceforge.net/p/mingw-w64/bugs/848/
+    /// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] {
+    /// use core::f32;
+    ///
+    /// let m = 10.0_f32;
+    /// let x = 4.0_f32;
+    /// let b = 60.0_f32;
+    ///
+    /// assert_eq!(f32::math::mul_add(m, x, b), 100.0);
+    /// assert_eq!(m * x + b, 100.0);
+    ///
+    /// let one_plus_eps = 1.0_f32 + f32::EPSILON;
+    /// let one_minus_eps = 1.0_f32 - f32::EPSILON;
+    /// let minus_one = -1.0_f32;
+    ///
+    /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
+    /// assert_eq!(
+    ///     f32::math::mul_add(one_plus_eps, one_minus_eps, minus_one),
+    ///     -f32::EPSILON * f32::EPSILON
+    /// );
+    /// // Different rounding with the non-fused multiply and add.
+    /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
+    /// # }
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::mul_add`]: ../../../std/primitive.f32.html#method.mul_add
+    #[inline]
+    #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    pub fn mul_add(x: f32, y: f32, z: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::fmaf32(x, y, z) }
     }
-    q
-}
 
-/// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let a: f32 = 7.0;
-/// let b = 4.0;
-/// assert_eq!(f32::rem_euclid(a, b), 3.0);
-/// assert_eq!(f32::rem_euclid(-a, b), 1.0);
-/// assert_eq!(f32::rem_euclid(a, -b), 3.0);
-/// assert_eq!(f32::rem_euclid(-a, -b), 1.0);
-/// // limitation due to round-off error
-/// assert!(f32::rem_euclid(-f32::EPSILON, 3.0) != 0.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::rem_euclid`]: ../../std/primitive.f32.html#method.rem_euclid
-#[inline]
-#[doc(alias = "modulo", alias = "mod")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn rem_euclid(x: f32, rhs: f32) -> f32 {
-    let r = x % rhs;
-    if r < 0.0 { r + rhs.abs() } else { r }
-}
+    /// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let a: f32 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(f32::math::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!(f32::math::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(f32::math::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!(f32::math::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::div_euclid`]: ../../../std/primitive.f32.html#method.div_euclid
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn div_euclid(x: f32, rhs: f32) -> f32 {
+        let q = trunc(x / rhs);
+        if x % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
 
-/// Experimental version of `powi` in `core`. See [`f32::powi`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let x = 2.0_f32;
-/// let abs_difference = (f32::powi(x, 2) - (x * x)).abs();
-/// assert!(abs_difference <= f32::EPSILON);
-///
-/// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::powi`]: ../../std/primitive.f32.html#method.powi
-#[inline]
-#[must_use = "method returns a new number and does not mutate the original value"]
-#[unstable(feature = "core_float_math", issue = "137578")]
-pub fn powi(x: f32, n: i32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::powif32(x, n) }
-}
+    /// Experimental version of `rem_euclid` in `core`. See [`f32::rem_euclid`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let a: f32 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(f32::math::rem_euclid(a, b), 3.0);
+    /// assert_eq!(f32::math::rem_euclid(-a, b), 1.0);
+    /// assert_eq!(f32::math::rem_euclid(a, -b), 3.0);
+    /// assert_eq!(f32::math::rem_euclid(-a, -b), 1.0);
+    /// // limitation due to round-off error
+    /// assert!(f32::math::rem_euclid(-f32::EPSILON, 3.0) != 0.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::rem_euclid`]: ../../../std/primitive.f32.html#method.rem_euclid
+    #[inline]
+    #[doc(alias = "modulo", alias = "mod")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn rem_euclid(x: f32, rhs: f32) -> f32 {
+        let r = x % rhs;
+        if r < 0.0 { r + rhs.abs() } else { r }
+    }
 
-/// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let positive = 4.0_f32;
-/// let negative = -4.0_f32;
-/// let negative_zero = -0.0_f32;
-///
-/// assert_eq!(f32::sqrt(positive), 2.0);
-/// assert!(f32::sqrt(negative).is_nan());
-/// assert_eq!(f32::sqrt(negative_zero), negative_zero);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::sqrt`]: ../../std/primitive.f32.html#method.sqrt
-#[inline]
-#[doc(alias = "squareRoot")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn sqrt(x: f32) -> f32 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::sqrtf32(x) }
-}
+    /// Experimental version of `powi` in `core`. See [`f32::powi`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let x = 2.0_f32;
+    /// let abs_difference = (f32::math::powi(x, 2) - (x * x)).abs();
+    /// assert!(abs_difference <= f32::EPSILON);
+    ///
+    /// assert_eq!(f32::math::powi(f32::NAN, 0), 1.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::powi`]: ../../../std/primitive.f32.html#method.powi
+    #[inline]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    pub fn powi(x: f32, n: i32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::powif32(x, n) }
+    }
 
-/// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let x = 3.0f32;
-/// let y = -3.0f32;
-///
-/// let abs_difference_x = (f32::abs_sub(x, 1.0) - 2.0).abs();
-/// let abs_difference_y = (f32::abs_sub(y, 1.0) - 0.0).abs();
-///
-/// assert!(abs_difference_x <= f32::EPSILON);
-/// assert!(abs_difference_y <= f32::EPSILON);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::abs_sub`]: ../../std/primitive.f32.html#method.abs_sub
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[deprecated(
-    since = "1.10.0",
-    note = "you probably meant `(self - other).abs()`: \
+    /// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let positive = 4.0_f32;
+    /// let negative = -4.0_f32;
+    /// let negative_zero = -0.0_f32;
+    ///
+    /// assert_eq!(f32::math::sqrt(positive), 2.0);
+    /// assert!(f32::math::sqrt(negative).is_nan());
+    /// assert_eq!(f32::math::sqrt(negative_zero), negative_zero);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::sqrt`]: ../../../std/primitive.f32.html#method.sqrt
+    #[inline]
+    #[doc(alias = "squareRoot")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sqrt(x: f32) -> f32 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::sqrtf32(x) }
+    }
+
+    /// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let x = 3.0f32;
+    /// let y = -3.0f32;
+    ///
+    /// let abs_difference_x = (f32::math::abs_sub(x, 1.0) - 2.0).abs();
+    /// let abs_difference_y = (f32::math::abs_sub(y, 1.0) - 0.0).abs();
+    ///
+    /// assert!(abs_difference_x <= f32::EPSILON);
+    /// assert!(abs_difference_y <= f32::EPSILON);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::abs_sub`]: ../../../std/primitive.f32.html#method.abs_sub
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[deprecated(
+        since = "1.10.0",
+        note = "you probably meant `(self - other).abs()`: \
             this operation is `(self - other).max(0.0)` \
             except that `abs_sub` also propagates NaNs (also \
             known as `fdimf` in C). If you truly need the positive \
             difference, consider using that expression or the C function \
             `fdimf`, depending on how you wish to handle NaN (please consider \
             filing an issue describing your use-case too)."
-)]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn abs_sub(x: f32, other: f32) -> f32 {
-    libm::fdimf(x, other)
-}
+    )]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn abs_sub(x: f32, other: f32) -> f32 {
+        libm::fdimf(x, other)
+    }
 
-/// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details.
-///
-/// # Unspecified precision
-///
-/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
-/// can even differ within the same execution from one invocation to the next.
-/// This function currently corresponds to the `cbrtf` from libc on Unix
-/// and Windows. Note that this might change in the future.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f32;
-///
-/// let x = 8.0f32;
-///
-/// // x^(1/3) - 2 == 0
-/// let abs_difference = (f32::cbrt(x) - 2.0).abs();
-///
-/// assert!(abs_difference <= f32::EPSILON);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f32::cbrt`]: ../../std/primitive.f32.html#method.cbrt
-#[inline]
-#[must_use = "method returns a new number and does not mutate the original value"]
-#[unstable(feature = "core_float_math", issue = "137578")]
-pub fn cbrt(x: f32) -> f32 {
-    libm::cbrtf(x)
+    /// Experimental version of `cbrt` in `core`. See [`f32::cbrt`] for details.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
+    /// can even differ within the same execution from one invocation to the next.
+    /// This function currently corresponds to the `cbrtf` from libc on Unix
+    /// and Windows. Note that this might change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f32;
+    ///
+    /// let x = 8.0f32;
+    ///
+    /// // x^(1/3) - 2 == 0
+    /// let abs_difference = (f32::math::cbrt(x) - 2.0).abs();
+    ///
+    /// assert!(abs_difference <= f32::EPSILON);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f32::cbrt`]: ../../../std/primitive.f32.html#method.cbrt
+    #[inline]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    pub fn cbrt(x: f32) -> f32 {
+        libm::cbrtf(x)
+    }
 }
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 76c4e5d1a6f..8fbf2cffbaf 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -12,7 +12,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::convert::FloatToInt;
-use crate::num::{FpCategory, libm};
+use crate::num::FpCategory;
 use crate::panic::const_assert;
 use crate::{intrinsics, mem};
 
@@ -1556,406 +1556,434 @@ impl f64 {
     }
 }
 
-/// Experimental version of `floor` in `core`. See [`f64::floor`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let f = 3.7_f64;
-/// let g = 3.0_f64;
-/// let h = -3.7_f64;
-///
-/// assert_eq!(f64::floor(f), 3.0);
-/// assert_eq!(f64::floor(g), 3.0);
-/// assert_eq!(f64::floor(h), -4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::floor`]: ../../std/primitive.f64.html#method.floor
-#[inline]
 #[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn floor(x: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::floorf64(x) }
-}
-
-/// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let f = 3.01_f64;
-/// let g = 4.0_f64;
-///
-/// assert_eq!(f64::ceil(f), 4.0);
-/// assert_eq!(f64::ceil(g), 4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
+/// Experimental implementations of floating point functions in `core`.
 ///
-/// [`f64::ceil`]: ../../std/primitive.f64.html#method.ceil
-#[inline]
-#[doc(alias = "ceiling")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn ceil(x: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::ceilf64(x) }
-}
+/// _The standalone functions in this module are for testing only.
+/// They will be stabilized as inherent methods._
+pub mod math {
+    use crate::intrinsics;
+    use crate::num::libm;
 
-/// Experimental version of `round` in `core`. See [`f64::round`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let f = 3.3_f64;
-/// let g = -3.3_f64;
-/// let h = -3.7_f64;
-/// let i = 3.5_f64;
-/// let j = 4.5_f64;
-///
-/// assert_eq!(f64::round(f), 3.0);
-/// assert_eq!(f64::round(g), -3.0);
-/// assert_eq!(f64::round(h), -4.0);
-/// assert_eq!(f64::round(i), 4.0);
-/// assert_eq!(f64::round(j), 5.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::round`]: ../../std/primitive.f64.html#method.round
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn round(x: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::roundf64(x) }
-}
+    /// Experimental version of `floor` in `core`. See [`f64::floor`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let f = 3.7_f64;
+    /// let g = 3.0_f64;
+    /// let h = -3.7_f64;
+    ///
+    /// assert_eq!(f64::math::floor(f), 3.0);
+    /// assert_eq!(f64::math::floor(g), 3.0);
+    /// assert_eq!(f64::math::floor(h), -4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::floor`]: ../../../std/primitive.f64.html#method.floor
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn floor(x: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::floorf64(x) }
+    }
 
-/// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let f = 3.3_f64;
-/// let g = -3.3_f64;
-/// let h = 3.5_f64;
-/// let i = 4.5_f64;
-///
-/// assert_eq!(f64::round_ties_even(f), 3.0);
-/// assert_eq!(f64::round_ties_even(g), -3.0);
-/// assert_eq!(f64::round_ties_even(h), 4.0);
-/// assert_eq!(f64::round_ties_even(i), 4.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::round_ties_even`]: ../../std/primitive.f64.html#method.round_ties_even
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn round_ties_even(x: f64) -> f64 {
-    intrinsics::round_ties_even_f64(x)
-}
+    /// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let f = 3.01_f64;
+    /// let g = 4.0_f64;
+    ///
+    /// assert_eq!(f64::math::ceil(f), 4.0);
+    /// assert_eq!(f64::math::ceil(g), 4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::ceil`]: ../../../std/primitive.f64.html#method.ceil
+    #[inline]
+    #[doc(alias = "ceiling")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn ceil(x: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::ceilf64(x) }
+    }
 
-/// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let f = 3.7_f64;
-/// let g = 3.0_f64;
-/// let h = -3.7_f64;
-///
-/// assert_eq!(f64::trunc(f), 3.0);
-/// assert_eq!(f64::trunc(g), 3.0);
-/// assert_eq!(f64::trunc(h), -3.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::trunc`]: ../../std/primitive.f64.html#method.trunc
-#[inline]
-#[doc(alias = "truncate")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn trunc(x: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::truncf64(x) }
-}
+    /// Experimental version of `round` in `core`. See [`f64::round`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let f = 3.3_f64;
+    /// let g = -3.3_f64;
+    /// let h = -3.7_f64;
+    /// let i = 3.5_f64;
+    /// let j = 4.5_f64;
+    ///
+    /// assert_eq!(f64::math::round(f), 3.0);
+    /// assert_eq!(f64::math::round(g), -3.0);
+    /// assert_eq!(f64::math::round(h), -4.0);
+    /// assert_eq!(f64::math::round(i), 4.0);
+    /// assert_eq!(f64::math::round(j), 5.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::round`]: ../../../std/primitive.f64.html#method.round
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round(x: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::roundf64(x) }
+    }
 
-/// Experimental version of `fract` in `core`. See [`f64::fract`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let x = 3.6_f64;
-/// let y = -3.6_f64;
-/// let abs_difference_x = (f64::fract(x) - 0.6).abs();
-/// let abs_difference_y = (f64::fract(y) - (-0.6)).abs();
-///
-/// assert!(abs_difference_x < 1e-10);
-/// assert!(abs_difference_y < 1e-10);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::fract`]: ../../std/primitive.f64.html#method.fract
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn fract(x: f64) -> f64 {
-    x - trunc(x)
-}
+    /// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for
+    /// details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let f = 3.3_f64;
+    /// let g = -3.3_f64;
+    /// let h = 3.5_f64;
+    /// let i = 4.5_f64;
+    ///
+    /// assert_eq!(f64::math::round_ties_even(f), 3.0);
+    /// assert_eq!(f64::math::round_ties_even(g), -3.0);
+    /// assert_eq!(f64::math::round_ties_even(h), 4.0);
+    /// assert_eq!(f64::math::round_ties_even(i), 4.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::round_ties_even`]: ../../../std/primitive.f64.html#method.round_ties_even
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn round_ties_even(x: f64) -> f64 {
+        intrinsics::round_ties_even_f64(x)
+    }
 
-/// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// # // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
-/// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] {
-/// use core::f64;
-///
-/// let m = 10.0_f64;
-/// let x = 4.0_f64;
-/// let b = 60.0_f64;
-///
-/// assert_eq!(f64::mul_add(m, x, b), 100.0);
-/// assert_eq!(m * x + b, 100.0);
-///
-/// let one_plus_eps = 1.0_f64 + f64::EPSILON;
-/// let one_minus_eps = 1.0_f64 - f64::EPSILON;
-/// let minus_one = -1.0_f64;
-///
-/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
-/// assert_eq!(f64::mul_add(one_plus_eps, one_minus_eps, minus_one), -f64::EPSILON * f64::EPSILON);
-/// // Different rounding with the non-fused multiply and add.
-/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
-/// # }
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::mul_add`]: ../../std/primitive.f64.html#method.mul_add
-#[inline]
-#[doc(alias = "fma", alias = "fusedMultiplyAdd")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn mul_add(x: f64, a: f64, b: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::fmaf64(x, a, b) }
-}
+    /// Experimental version of `trunc` in `core`. See [`f64::trunc`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let f = 3.7_f64;
+    /// let g = 3.0_f64;
+    /// let h = -3.7_f64;
+    ///
+    /// assert_eq!(f64::math::trunc(f), 3.0);
+    /// assert_eq!(f64::math::trunc(g), 3.0);
+    /// assert_eq!(f64::math::trunc(h), -3.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::trunc`]: ../../../std/primitive.f64.html#method.trunc
+    #[inline]
+    #[doc(alias = "truncate")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn trunc(x: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::truncf64(x) }
+    }
 
-/// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let a: f64 = 7.0;
-/// let b = 4.0;
-/// assert_eq!(f64::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0
-/// assert_eq!(f64::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0
-/// assert_eq!(f64::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0
-/// assert_eq!(f64::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::div_euclid`]: ../../std/primitive.f64.html#method.div_euclid
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn div_euclid(x: f64, rhs: f64) -> f64 {
-    let q = trunc(x / rhs);
-    if x % rhs < 0.0 {
-        return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+    /// Experimental version of `fract` in `core`. See [`f64::fract`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let x = 3.6_f64;
+    /// let y = -3.6_f64;
+    /// let abs_difference_x = (f64::math::fract(x) - 0.6).abs();
+    /// let abs_difference_y = (f64::math::fract(y) - (-0.6)).abs();
+    ///
+    /// assert!(abs_difference_x < 1e-10);
+    /// assert!(abs_difference_y < 1e-10);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::fract`]: ../../../std/primitive.f64.html#method.fract
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn fract(x: f64) -> f64 {
+        x - trunc(x)
     }
-    q
-}
 
-/// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let a: f64 = 7.0;
-/// let b = 4.0;
-/// assert_eq!(f64::rem_euclid(a, b), 3.0);
-/// assert_eq!(f64::rem_euclid(-a, b), 1.0);
-/// assert_eq!(f64::rem_euclid(a, -b), 3.0);
-/// assert_eq!(f64::rem_euclid(-a, -b), 1.0);
-/// // limitation due to round-off error
-/// assert!(f64::rem_euclid(-f64::EPSILON, 3.0) != 0.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::rem_euclid`]: ../../std/primitive.f64.html#method.rem_euclid
-#[inline]
-#[doc(alias = "modulo", alias = "mod")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn rem_euclid(x: f64, rhs: f64) -> f64 {
-    let r = x % rhs;
-    if r < 0.0 { r + rhs.abs() } else { r }
-}
+    /// Experimental version of `mul_add` in `core`. See [`f64::mul_add`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// # // FIXME(#140515): mingw has an incorrect fma
+    /// # // https://sourceforge.net/p/mingw-w64/bugs/848/
+    /// # #[cfg(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")))] {
+    /// use core::f64;
+    ///
+    /// let m = 10.0_f64;
+    /// let x = 4.0_f64;
+    /// let b = 60.0_f64;
+    ///
+    /// assert_eq!(f64::math::mul_add(m, x, b), 100.0);
+    /// assert_eq!(m * x + b, 100.0);
+    ///
+    /// let one_plus_eps = 1.0_f64 + f64::EPSILON;
+    /// let one_minus_eps = 1.0_f64 - f64::EPSILON;
+    /// let minus_one = -1.0_f64;
+    ///
+    /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
+    /// assert_eq!(
+    ///     f64::math::mul_add(one_plus_eps, one_minus_eps, minus_one),
+    ///     -f64::EPSILON * f64::EPSILON
+    /// );
+    /// // Different rounding with the non-fused multiply and add.
+    /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
+    /// # }
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::mul_add`]: ../../../std/primitive.f64.html#method.mul_add
+    #[inline]
+    #[doc(alias = "fma", alias = "fusedMultiplyAdd")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn mul_add(x: f64, a: f64, b: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::fmaf64(x, a, b) }
+    }
 
-/// Experimental version of `powi` in `core`. See [`f64::powi`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let x = 2.0_f64;
-/// let abs_difference = (f64::powi(x, 2) - (x * x)).abs();
-/// assert!(abs_difference <= f64::EPSILON);
-///
-/// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::powi`]: ../../std/primitive.f64.html#method.powi
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn powi(x: f64, n: i32) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::powif64(x, n) }
-}
+    /// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let a: f64 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(f64::math::div_euclid(a, b), 1.0); // 7.0 > 4.0 * 1.0
+    /// assert_eq!(f64::math::div_euclid(-a, b), -2.0); // -7.0 >= 4.0 * -2.0
+    /// assert_eq!(f64::math::div_euclid(a, -b), -1.0); // 7.0 >= -4.0 * -1.0
+    /// assert_eq!(f64::math::div_euclid(-a, -b), 2.0); // -7.0 >= -4.0 * 2.0
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::div_euclid`]: ../../../std/primitive.f64.html#method.div_euclid
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn div_euclid(x: f64, rhs: f64) -> f64 {
+        let q = trunc(x / rhs);
+        if x % rhs < 0.0 {
+            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
 
-/// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let positive = 4.0_f64;
-/// let negative = -4.0_f64;
-/// let negative_zero = -0.0_f64;
-///
-/// assert_eq!(f64::sqrt(positive), 2.0);
-/// assert!(f64::sqrt(negative).is_nan());
-/// assert_eq!(f64::sqrt(negative_zero), negative_zero);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::sqrt`]: ../../std/primitive.f64.html#method.sqrt
-#[inline]
-#[doc(alias = "squareRoot")]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn sqrt(x: f64) -> f64 {
-    // SAFETY: intrinsic with no preconditions
-    unsafe { intrinsics::sqrtf64(x) }
-}
+    /// Experimental version of `rem_euclid` in `core`. See [`f64::rem_euclid`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let a: f64 = 7.0;
+    /// let b = 4.0;
+    /// assert_eq!(f64::math::rem_euclid(a, b), 3.0);
+    /// assert_eq!(f64::math::rem_euclid(-a, b), 1.0);
+    /// assert_eq!(f64::math::rem_euclid(a, -b), 3.0);
+    /// assert_eq!(f64::math::rem_euclid(-a, -b), 1.0);
+    /// // limitation due to round-off error
+    /// assert!(f64::math::rem_euclid(-f64::EPSILON, 3.0) != 0.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::rem_euclid`]: ../../../std/primitive.f64.html#method.rem_euclid
+    #[inline]
+    #[doc(alias = "modulo", alias = "mod")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn rem_euclid(x: f64, rhs: f64) -> f64 {
+        let r = x % rhs;
+        if r < 0.0 { r + rhs.abs() } else { r }
+    }
 
-/// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let x = 3.0_f64;
-/// let y = -3.0_f64;
-///
-/// let abs_difference_x = (f64::abs_sub(x, 1.0) - 2.0).abs();
-/// let abs_difference_y = (f64::abs_sub(y, 1.0) - 0.0).abs();
-///
-/// assert!(abs_difference_x < 1e-10);
-/// assert!(abs_difference_y < 1e-10);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::abs_sub`]: ../../std/primitive.f64.html#method.abs_sub
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[deprecated(
-    since = "1.10.0",
-    note = "you probably meant `(self - other).abs()`: \
+    /// Experimental version of `powi` in `core`. See [`f64::powi`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let x = 2.0_f64;
+    /// let abs_difference = (f64::math::powi(x, 2) - (x * x)).abs();
+    /// assert!(abs_difference <= f64::EPSILON);
+    ///
+    /// assert_eq!(f64::math::powi(f64::NAN, 0), 1.0);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::powi`]: ../../../std/primitive.f64.html#method.powi
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(x: f64, n: i32) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::powif64(x, n) }
+    }
+
+    /// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let positive = 4.0_f64;
+    /// let negative = -4.0_f64;
+    /// let negative_zero = -0.0_f64;
+    ///
+    /// assert_eq!(f64::math::sqrt(positive), 2.0);
+    /// assert!(f64::math::sqrt(negative).is_nan());
+    /// assert_eq!(f64::math::sqrt(negative_zero), negative_zero);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::sqrt`]: ../../../std/primitive.f64.html#method.sqrt
+    #[inline]
+    #[doc(alias = "squareRoot")]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn sqrt(x: f64) -> f64 {
+        // SAFETY: intrinsic with no preconditions
+        unsafe { intrinsics::sqrtf64(x) }
+    }
+
+    /// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let x = 3.0_f64;
+    /// let y = -3.0_f64;
+    ///
+    /// let abs_difference_x = (f64::math::abs_sub(x, 1.0) - 2.0).abs();
+    /// let abs_difference_y = (f64::math::abs_sub(y, 1.0) - 0.0).abs();
+    ///
+    /// assert!(abs_difference_x < 1e-10);
+    /// assert!(abs_difference_y < 1e-10);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::abs_sub`]: ../../../std/primitive.f64.html#method.abs_sub
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[deprecated(
+        since = "1.10.0",
+        note = "you probably meant `(self - other).abs()`: \
                 this operation is `(self - other).max(0.0)` \
                 except that `abs_sub` also propagates NaNs (also \
                 known as `fdim` in C). If you truly need the positive \
                 difference, consider using that expression or the C function \
                 `fdim`, depending on how you wish to handle NaN (please consider \
                 filing an issue describing your use-case too)."
-)]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn abs_sub(x: f64, other: f64) -> f64 {
-    libm::fdim(x, other)
-}
+    )]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn abs_sub(x: f64, other: f64) -> f64 {
+        libm::fdim(x, other)
+    }
 
-/// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(core_float_math)]
-///
-/// use core::f64;
-///
-/// let x = 8.0_f64;
-///
-/// // x^(1/3) - 2 == 0
-/// let abs_difference = (f64::cbrt(x) - 2.0).abs();
-///
-/// assert!(abs_difference < 1e-10);
-/// ```
-///
-/// _This standalone function is for testing only. It will be stabilized as an inherent method._
-///
-/// [`f64::cbrt`]: ../../std/primitive.f64.html#method.cbrt
-#[inline]
-#[unstable(feature = "core_float_math", issue = "137578")]
-#[must_use = "method returns a new number and does not mutate the original value"]
-pub fn cbrt(x: f64) -> f64 {
-    libm::cbrt(x)
+    /// Experimental version of `cbrt` in `core`. See [`f64::cbrt`] for details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(core_float_math)]
+    ///
+    /// use core::f64;
+    ///
+    /// let x = 8.0_f64;
+    ///
+    /// // x^(1/3) - 2 == 0
+    /// let abs_difference = (f64::math::cbrt(x) - 2.0).abs();
+    ///
+    /// assert!(abs_difference < 1e-10);
+    /// ```
+    ///
+    /// _This standalone function is for testing only.
+    /// It will be stabilized as an inherent method._
+    ///
+    /// [`f64::cbrt`]: ../../../std/primitive.f64.html#method.cbrt
+    #[inline]
+    #[unstable(feature = "core_float_math", issue = "137578")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn cbrt(x: f64) -> f64 {
+        libm::cbrt(x)
+    }
 }
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 54d79beca95..098ce4531f0 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -67,8 +67,8 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
 #[rustc_on_unimplemented(
-    on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
-    on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
+    on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
+    on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
     message = "cannot add `{Rhs}` to `{Self}`",
     label = "no implementation for `{Self} + {Rhs}`",
     append_const_msg
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index e9014458b48..df48c104410 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -62,7 +62,7 @@ use crate::marker::Tuple;
         note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
     ),
     on(
-        _Self = "unsafe fn",
+        Self = "unsafe fn",
         note = "unsafe function cannot be called generically without an unsafe block",
         // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
         label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
@@ -149,7 +149,7 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
         note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
     ),
     on(
-        _Self = "unsafe fn",
+        Self = "unsafe fn",
         note = "unsafe function cannot be called generically without an unsafe block",
         // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
         label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
@@ -228,7 +228,7 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
         note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
     ),
     on(
-        _Self = "unsafe fn",
+        Self = "unsafe fn",
         note = "unsafe function cannot be called generically without an unsafe block",
         // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
         label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 46e19bed43a..8092fa9eb2f 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -144,17 +144,17 @@ pub trait Index<Idx: ?Sized> {
 #[lang = "index_mut"]
 #[rustc_on_unimplemented(
     on(
-        _Self = "&str",
+        Self = "&str",
         note = "you can use `.chars().nth()` or `.bytes().nth()`
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
     on(
-        _Self = "str",
+        Self = "str",
         note = "you can use `.chars().nth()` or `.bytes().nth()`
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
     on(
-        _Self = "alloc::string::String",
+        Self = "alloc::string::String",
         note = "you can use `.chars().nth()` or `.bytes().nth()`
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 3ba2957526f..bac8ffb074b 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -117,12 +117,12 @@ use crate::ops::ControlFlow;
     on(
         all(from_desugaring = "TryBlock"),
         message = "a `try` block must return `Result` or `Option` \
-                    (or another type that implements `{Try}`)",
+                    (or another type that implements `{This}`)",
         label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
     ),
     on(
         all(from_desugaring = "QuestionMark"),
-        message = "the `?` operator can only be applied to values that implement `{Try}`",
+        message = "the `?` operator can only be applied to values that implement `{This}`",
         label = "the `?` operator cannot be applied to type `{Self}`"
     )
 )]
@@ -226,7 +226,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::result::Result<T, E>",
+            Self = "core::result::Result<T, E>",
             R = "core::option::Option<core::convert::Infallible>",
         ),
         message = "the `?` operator can only be used on `Result`s, not `Option`s, \
@@ -237,7 +237,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::result::Result<T, E>",
+            Self = "core::result::Result<T, E>",
         ),
         // There's a special error message in the trait selection code for
         // `From` in `?`, so this is not shown for result-in-result errors,
@@ -250,7 +250,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::option::Option<T>",
+            Self = "core::option::Option<T>",
             R = "core::result::Result<T, E>",
         ),
         message = "the `?` operator can only be used on `Option`s, not `Result`s, \
@@ -261,7 +261,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::option::Option<T>",
+            Self = "core::option::Option<T>",
         ),
         // `Option`-in-`Option` always works, as there's only one possible
         // residual, so this can also be phrased strongly.
@@ -273,7 +273,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::ops::control_flow::ControlFlow<B, C>",
+            Self = "core::ops::control_flow::ControlFlow<B, C>",
             R = "core::ops::control_flow::ControlFlow<B, C>",
         ),
         message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
@@ -285,7 +285,7 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "core::ops::control_flow::ControlFlow<B, C>",
+            Self = "core::ops::control_flow::ControlFlow<B, C>",
             // `R` is not a `ControlFlow`, as that case was matched previously
         ),
         message = "the `?` operator can only be used on `ControlFlow`s \
@@ -297,7 +297,7 @@ pub trait Try: FromResidual {
         all(from_desugaring = "QuestionMark"),
         message = "the `?` operator can only be used in {ItemContext} \
                     that returns `Result` or `Option` \
-                    (or another type that implements `{FromResidual}`)",
+                    (or another type that implements `{This}`)",
         label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
         parent_label = "this function should return `Result` or `Option` to accept `?`"
     ),
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index aed5a043c11..1d264b26076 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -120,20 +120,22 @@
 //!
 //! Rust guarantees to optimize the following types `T` such that
 //! [`Option<T>`] has the same size, alignment, and [function call ABI] as `T`. In some
-//! of these cases, Rust further guarantees that
-//! `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and
-//! produces `Option::<T>::None`. These cases are identified by the
-//! second column:
-//!
-//! | `T`                                                                 | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
-//! |---------------------------------------------------------------------|----------------------------------------------------------------------|
-//! | [`Box<U>`] (specifically, only `Box<U, Global>`)                    | when `U: Sized`                                                      |
-//! | `&U`                                                                | when `U: Sized`                                                      |
-//! | `&mut U`                                                            | when `U: Sized`                                                      |
-//! | `fn`, `extern "C" fn`[^extern_fn]                                   | always                                                               |
-//! | [`num::NonZero*`]                                                   | always                                                               |
-//! | [`ptr::NonNull<U>`]                                                 | when `U: Sized`                                                      |
-//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type                                     |
+//! of these cases, Rust further guarantees the following:
+//! - `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and produces
+//!   `Option::<T>::None`
+//! - `transmute::<_, [u8; size_of::<T>()]>(Option::<T>::None)` is sound and produces
+//!   `[0u8; size_of::<T>()]`
+//! These cases are identified by the second column:
+//!
+//! | `T`                                                                 | Transmuting between `[0u8; size_of::<T>()]` and `Option::<T>::None` sound? |
+//! |---------------------------------------------------------------------|----------------------------------------------------------------------------|
+//! | [`Box<U>`] (specifically, only `Box<U, Global>`)                    | when `U: Sized`                                                            |
+//! | `&U`                                                                | when `U: Sized`                                                            |
+//! | `&mut U`                                                            | when `U: Sized`                                                            |
+//! | `fn`, `extern "C" fn`[^extern_fn]                                   | always                                                                     |
+//! | [`num::NonZero*`]                                                   | always                                                                     |
+//! | [`ptr::NonNull<U>`]                                                 | when `U: Sized`                                                            |
+//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type                                           |
 //!
 //! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`)
 //!
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 257424b355f..aad073cc8cd 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1419,7 +1419,7 @@ impl<Ptr: DerefMut> Pin<Ptr> {
     #[stable(feature = "pin_deref_mut", since = "1.84.0")]
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline(always)]
-    pub fn as_deref_mut(self: Pin<&mut Pin<Ptr>>) -> Pin<&mut Ptr::Target> {
+    pub fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut Ptr::Target> {
         // SAFETY: What we're asserting here is that going from
         //
         //     Pin<&mut Pin<Ptr>>
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 35089b4853d..19ed7599a51 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -66,6 +66,32 @@ impl<T: ?Sized> *const T {
         self as _
     }
 
+    /// Try to cast to a pointer of another type by checking aligment.
+    ///
+    /// If the pointer is properly aligned to the target type, it will be
+    /// cast to the target type. Otherwise, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(pointer_try_cast_aligned)]
+    ///
+    /// let x = 0u64;
+    ///
+    /// let aligned: *const u64 = &x;
+    /// let unaligned = unsafe { aligned.byte_add(1) };
+    ///
+    /// assert!(aligned.try_cast_aligned::<u32>().is_some());
+    /// assert!(unaligned.try_cast_aligned::<u32>().is_none());
+    /// ```
+    #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub fn try_cast_aligned<U>(self) -> Option<*const U> {
+        if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
+    }
+
     /// Uses the address value in a new pointer of another type.
     ///
     /// This operation will ignore the address part of its `meta` operand and discard existing
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index bd6c4daa509..35a909f6904 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -405,16 +405,6 @@ mod alignment;
 #[unstable(feature = "ptr_alignment_type", issue = "102070")]
 pub use alignment::Alignment;
 
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::copy;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::copy_nonoverlapping;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::write_bytes;
-
 mod metadata;
 #[unstable(feature = "ptr_metadata", issue = "81513")]
 pub use metadata::{DynMetadata, Pointee, Thin, from_raw_parts, from_raw_parts_mut, metadata};
@@ -430,6 +420,289 @@ pub use unique::Unique;
 mod const_ptr;
 mod mut_ptr;
 
+// Some functions are defined here because they accidentally got made
+// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
+// (`transmute` also falls into this category, but it cannot be wrapped due to the
+// check that `T` and `U` have the same size.)
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination must *not* overlap.
+///
+/// For regions of memory which might overlap, use [`copy`] instead.
+///
+/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
+/// with the source and destination arguments swapped,
+/// and `count` counting the number of `T`s instead of bytes.
+///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
+/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// * The region of memory beginning at `src` with a size of `count *
+///   size_of::<T>()` bytes must *not* overlap with the region of memory
+///   beginning at `dst` with the same size.
+///
+/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Manually implement [`Vec::append`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+///     let src_len = src.len();
+///     let dst_len = dst.len();
+///
+///     // Ensure that `dst` has enough capacity to hold all of `src`.
+///     dst.reserve(src_len);
+///
+///     unsafe {
+///         // The call to add is always safe because `Vec` will never
+///         // allocate more than `isize::MAX` bytes.
+///         let dst_ptr = dst.as_mut_ptr().add(dst_len);
+///         let src_ptr = src.as_ptr();
+///
+///         // Truncate `src` without dropping its contents. We do this first,
+///         // to avoid problems in case something further down panics.
+///         src.set_len(0);
+///
+///         // The two regions cannot overlap because mutable references do
+///         // not alias, and two different vectors cannot own the same
+///         // memory.
+///         ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
+///
+///         // Notify `dst` that it now holds the contents of `src`.
+///         dst.set_len(dst_len + src_len);
+///     }
+/// }
+///
+/// let mut a = vec!['r'];
+/// let mut b = vec!['u', 's', 't'];
+///
+/// append(&mut a, &mut b);
+///
+/// assert_eq!(a, &['r', 'u', 's', 't']);
+/// assert!(b.is_empty());
+/// ```
+///
+/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
+#[doc(alias = "memcpy")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+    ub_checks::assert_unsafe_precondition!(
+        check_language_ub,
+        "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
+        and the specified memory ranges do not overlap",
+        (
+            src: *const () = src as *const (),
+            dst: *mut () = dst as *mut (),
+            size: usize = size_of::<T>(),
+            align: usize = align_of::<T>(),
+            count: usize = count,
+        ) => {
+            let zero_size = count == 0 || size == 0;
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+                && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
+        }
+    );
+
+    // SAFETY: the safety contract for `copy_nonoverlapping` must be
+    // upheld by the caller.
+    unsafe { crate::intrinsics::copy_nonoverlapping(src, dst, count) }
+}
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination may overlap.
+///
+/// If the source and destination will *never* overlap,
+/// [`copy_nonoverlapping`] can be used instead.
+///
+/// `copy` is semantically equivalent to C's [`memmove`], but
+/// with the source and destination arguments swapped,
+/// and `count` counting the number of `T`s instead of bytes.
+/// Copying takes place as if the bytes were copied from `src`
+/// to a temporary array and then copied from the array to `dst`.
+///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
+/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
+///   when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
+///   overlap, the `dst` pointer must not be invalidated by `src` reads.)
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Efficiently create a Rust vector from an unsafe buffer:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// # Safety
+/// ///
+/// /// * `ptr` must be correctly aligned for its type and non-zero.
+/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
+/// /// * Those elements must not be used after calling this function unless `T: Copy`.
+/// # #[allow(dead_code)]
+/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
+///     let mut dst = Vec::with_capacity(elts);
+///
+///     // SAFETY: Our precondition ensures the source is aligned and valid,
+///     // and `Vec::with_capacity` ensures that we have usable space to write them.
+///     unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
+///
+///     // SAFETY: We created it with this much capacity earlier,
+///     // and the previous `copy` has initialized these elements.
+///     unsafe { dst.set_len(elts); }
+///     dst
+/// }
+/// ```
+#[doc(alias = "memmove")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_copy"]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    // SAFETY: the safety contract for `copy` must be upheld by the caller.
+    unsafe {
+        ub_checks::assert_unsafe_precondition!(
+            check_language_ub,
+            "ptr::copy requires that both pointer arguments are aligned and non-null",
+            (
+                src: *const () = src as *const (),
+                dst: *mut () = dst as *mut (),
+                align: usize = align_of::<T>(),
+                zero_size: bool = T::IS_ZST || count == 0,
+            ) =>
+            ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+                && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+        );
+        crate::intrinsics::copy(src, dst, count)
+    }
+}
+
+/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
+/// `val`.
+///
+/// `write_bytes` is similar to C's [`memset`], but sets `count *
+/// size_of::<T>()` bytes to `val`.
+///
+/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be properly aligned.
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointer must be properly aligned.
+///
+/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
+/// later if the written bytes are not a valid representation of some `T`. For instance, the
+/// following is an **incorrect** use of this function:
+///
+/// ```rust,no_run
+/// unsafe {
+///     let mut value: u8 = 0;
+///     let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
+///     let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
+///     ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
+///     let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
+/// }
+/// ```
+///
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::ptr;
+///
+/// let mut vec = vec![0u32; 4];
+/// unsafe {
+///     let vec_ptr = vec.as_mut_ptr();
+///     ptr::write_bytes(vec_ptr, 0xfe, 2);
+/// }
+/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
+/// ```
+#[doc(alias = "memset")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_write_bytes"]
+pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
+    // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
+    unsafe {
+        ub_checks::assert_unsafe_precondition!(
+            check_language_ub,
+            "ptr::write_bytes requires that the destination pointer is aligned and non-null",
+            (
+                addr: *const () = dst as *const (),
+                align: usize = align_of::<T>(),
+                zero_size: bool = T::IS_ZST || count == 0,
+            ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
+        );
+        crate::intrinsics::write_bytes(dst, val, count)
+    }
+}
+
 /// Executes the destructor (if any) of the pointed-to value.
 ///
 /// This is almost the same as calling [`ptr::read`] and discarding
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 9cf251742d4..53aa3ab4938 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -48,6 +48,32 @@ impl<T: ?Sized> *mut T {
         self as _
     }
 
+    /// Try to cast to a pointer of another type by checking aligment.
+    ///
+    /// If the pointer is properly aligned to the target type, it will be
+    /// cast to the target type. Otherwise, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(pointer_try_cast_aligned)]
+    ///
+    /// let mut x = 0u64;
+    ///
+    /// let aligned: *mut u64 = &mut x;
+    /// let unaligned = unsafe { aligned.byte_add(1) };
+    ///
+    /// assert!(aligned.try_cast_aligned::<u32>().is_some());
+    /// assert!(unaligned.try_cast_aligned::<u32>().is_none());
+    /// ```
+    #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub fn try_cast_aligned<U>(self) -> Option<*mut U> {
+        if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
+    }
+
     /// Uses the address value in a new pointer of another type.
     ///
     /// This operation will ignore the address part of its `meta` operand and discard existing
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 8b31328de04..7c9b898f8e9 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -490,6 +490,33 @@ impl<T: ?Sized> NonNull<T> {
         unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
     }
 
+    /// Try to cast to a pointer of another type by checking aligment.
+    ///
+    /// If the pointer is properly aligned to the target type, it will be
+    /// cast to the target type. Otherwise, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(pointer_try_cast_aligned)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let mut x = 0u64;
+    ///
+    /// let aligned = NonNull::from_mut(&mut x);
+    /// let unaligned = unsafe { aligned.byte_add(1) };
+    ///
+    /// assert!(aligned.try_cast_aligned::<u32>().is_some());
+    /// assert!(unaligned.try_cast_aligned::<u32>().is_none());
+    /// ```
+    #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub fn try_cast_aligned<U>(self) -> Option<NonNull<U>> {
+        if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
+    }
+
     /// Adds an offset to a pointer.
     ///
     /// `count` is in units of T; e.g., a `count` of 3 represents a pointer
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index aafa19c0dd3..409bad9f061 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -161,7 +161,7 @@ mod private_slice_index {
 #[rustc_on_unimplemented(
     on(T = "str", label = "string indices are ranges of `usize`",),
     on(
-        all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"),
+        all(any(T = "str", T = "&str", T = "alloc::string::String"), Self = "{integer}"),
         note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
                 for more information, see chapter 8 in The Book: \
                 <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 058491b53a1..26520123a8d 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2986,7 +2986,7 @@ impl<T> [T] {
         self.binary_search_by(|k| f(k).cmp(b))
     }
 
-    /// Sorts the slice **without** preserving the initial order of equal elements.
+    /// Sorts the slice in ascending order **without** preserving the initial order of equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
@@ -3047,8 +3047,8 @@ impl<T> [T] {
         sort::unstable::sort(self, &mut T::lt);
     }
 
-    /// Sorts the slice with a comparison function, **without** preserving the initial order of
-    /// equal elements.
+    /// Sorts the slice in ascending order with a comparison function, **without** preserving the
+    /// initial order of equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
@@ -3102,8 +3102,8 @@ impl<T> [T] {
         sort::unstable::sort(self, &mut |a, b| compare(a, b) == Ordering::Less);
     }
 
-    /// Sorts the slice with a key extraction function, **without** preserving the initial order of
-    /// equal elements.
+    /// Sorts the slice in ascending order with a key extraction function, **without** preserving
+    /// the initial order of equal elements.
     ///
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
@@ -4383,7 +4383,7 @@ impl<T> [T] {
     /// assert_eq!(first_three, &['a', 'b', 'c']);
     /// ```
     ///
-    /// Splitting off the last two elements of a slice:
+    /// Splitting off a slice starting with the third element:
     ///
     /// ```
     /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
@@ -4449,7 +4449,7 @@ impl<T> [T] {
     /// assert_eq!(first_three, &mut ['a', 'b', 'c']);
     /// ```
     ///
-    /// Taking the last two elements of a slice:
+    /// Splitting off a slice starting with the third element:
     ///
     /// ```
     /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
diff --git a/library/core/src/slice/sort/select.rs b/library/core/src/slice/sort/select.rs
index c4808b1065d..82194db7fd8 100644
--- a/library/core/src/slice/sort/select.rs
+++ b/library/core/src/slice/sort/select.rs
@@ -6,7 +6,7 @@
 //! for pivot selection. Using this as a fallback ensures O(n) worst case running time with
 //! better performance than one would get using heapsort as fallback.
 
-use crate::cfg_match;
+use crate::cfg_select;
 use crate::mem::{self, SizedTypeProperties};
 #[cfg(not(feature = "optimize_for_size"))]
 use crate::slice::sort::shared::pivot::choose_pivot;
@@ -42,7 +42,7 @@ where
         let min_idx = min_index(v, &mut is_less).unwrap();
         v.swap(min_idx, index);
     } else {
-        cfg_match! {
+        cfg_select! {
             feature = "optimize_for_size" => {
                 median_of_medians(v, &mut is_less, index);
             }
diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs
index a36e5f7801d..8b4e5c0c8c3 100644
--- a/library/core/src/slice/sort/stable/mod.rs
+++ b/library/core/src/slice/sort/stable/mod.rs
@@ -7,7 +7,7 @@ use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::slice::sort::shared::smallsort::{
     SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left,
 };
-use crate::{cfg_match, intrinsics};
+use crate::{cfg_select, intrinsics};
 
 pub(crate) mod merge;
 
@@ -39,13 +39,13 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
         return;
     }
 
-    cfg_match! {
+    cfg_select! {
         any(feature = "optimize_for_size", target_pointer_width = "16") => {
             // Unlike driftsort, mergesort only requires len / 2,
             // not len - len / 2.
             let alloc_len = len / 2;
 
-            cfg_match! {
+            cfg_select! {
                 target_pointer_width = "16" => {
                     let mut heap_buf = BufT::with_capacity(alloc_len);
                     let scratch = heap_buf.as_uninit_slice_mut();
diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs
index b6c2e05a06a..d4df8d3a264 100644
--- a/library/core/src/slice/sort/unstable/mod.rs
+++ b/library/core/src/slice/sort/unstable/mod.rs
@@ -5,7 +5,7 @@ use crate::mem::SizedTypeProperties;
 use crate::slice::sort::shared::find_existing_run;
 #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
 use crate::slice::sort::shared::smallsort::insertion_sort_shift_left;
-use crate::{cfg_match, intrinsics};
+use crate::{cfg_select, intrinsics};
 
 pub(crate) mod heapsort;
 pub(crate) mod quicksort;
@@ -30,7 +30,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) {
         return;
     }
 
-    cfg_match! {
+    cfg_select! {
         any(feature = "optimize_for_size", target_pointer_width = "16") => {
             heapsort::heapsort(v, is_less);
         }
diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs
index 7e6cfb55990..98efee242eb 100644
--- a/library/core/src/slice/sort/unstable/quicksort.rs
+++ b/library/core/src/slice/sort/unstable/quicksort.rs
@@ -9,7 +9,7 @@ use crate::slice::sort::shared::pivot::choose_pivot;
 use crate::slice::sort::shared::smallsort::UnstableSmallSortTypeImpl;
 #[cfg(not(feature = "optimize_for_size"))]
 use crate::slice::sort::unstable::heapsort;
-use crate::{cfg_match, intrinsics, ptr};
+use crate::{cfg_select, intrinsics, ptr};
 
 /// Sorts `v` recursively.
 ///
@@ -142,7 +142,7 @@ const fn inst_partition<T, F: FnMut(&T, &T) -> bool>() -> fn(&mut [T], &T, &mut
     if size_of::<T>() <= MAX_BRANCHLESS_PARTITION_SIZE {
         // Specialize for types that are relatively cheap to copy, where branchless optimizations
         // have large leverage e.g. `u64` and `String`.
-        cfg_match! {
+        cfg_select! {
             feature = "optimize_for_size" => {
                 partition_lomuto_branchless_simple::<T, F>
             }
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 84c7f1aafe1..bd5a58d74ba 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -193,7 +193,7 @@
 //!
 //! A simple spinlock:
 //!
-//! ```
+//! ```ignore-wasm
 //! use std::sync::Arc;
 //! use std::sync::atomic::{AtomicUsize, Ordering};
 //! use std::{hint, thread};
@@ -622,7 +622,7 @@ impl AtomicBool {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```ignore-wasm
     /// #![feature(atomic_from_mut)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
@@ -653,7 +653,7 @@ impl AtomicBool {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```rust,ignore-wasm
     /// #![feature(atomic_from_mut)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
@@ -1548,7 +1548,7 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```ignore-wasm
     /// #![feature(atomic_from_mut)]
     /// use std::ptr::null_mut;
     /// use std::sync::atomic::{AtomicPtr, Ordering};
@@ -1585,7 +1585,7 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Examples
     ///
-    /// ```
+    /// ```ignore-wasm
     /// #![feature(atomic_from_mut)]
     /// use std::ptr::null_mut;
     /// use std::sync::atomic::{AtomicPtr, Ordering};
@@ -2692,7 +2692,7 @@ macro_rules! atomic_int {
             ///
             /// # Examples
             ///
-            /// ```
+            /// ```ignore-wasm
             /// #![feature(atomic_from_mut)]
             #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
             ///
@@ -2725,7 +2725,7 @@ macro_rules! atomic_int {
             ///
             /// # Examples
             ///
-            /// ```
+            /// ```ignore-wasm
             /// #![feature(atomic_from_mut)]
             #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
             ///
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs
index 9b551643bae..36f1937bedf 100644
--- a/library/coretests/tests/floats/f32.rs
+++ b/library/coretests/tests/floats/f32.rs
@@ -215,88 +215,88 @@ fn test_classify() {
 
 #[test]
 fn test_floor() {
-    assert_approx_eq!(f32::floor(1.0f32), 1.0f32);
-    assert_approx_eq!(f32::floor(1.3f32), 1.0f32);
-    assert_approx_eq!(f32::floor(1.5f32), 1.0f32);
-    assert_approx_eq!(f32::floor(1.7f32), 1.0f32);
-    assert_approx_eq!(f32::floor(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::floor(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::floor(-1.0f32), -1.0f32);
-    assert_approx_eq!(f32::floor(-1.3f32), -2.0f32);
-    assert_approx_eq!(f32::floor(-1.5f32), -2.0f32);
-    assert_approx_eq!(f32::floor(-1.7f32), -2.0f32);
+    assert_approx_eq!(f32::math::floor(1.0f32), 1.0f32);
+    assert_approx_eq!(f32::math::floor(1.3f32), 1.0f32);
+    assert_approx_eq!(f32::math::floor(1.5f32), 1.0f32);
+    assert_approx_eq!(f32::math::floor(1.7f32), 1.0f32);
+    assert_approx_eq!(f32::math::floor(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::floor(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::floor(-1.0f32), -1.0f32);
+    assert_approx_eq!(f32::math::floor(-1.3f32), -2.0f32);
+    assert_approx_eq!(f32::math::floor(-1.5f32), -2.0f32);
+    assert_approx_eq!(f32::math::floor(-1.7f32), -2.0f32);
 }
 
 #[test]
 fn test_ceil() {
-    assert_approx_eq!(f32::ceil(1.0f32), 1.0f32);
-    assert_approx_eq!(f32::ceil(1.3f32), 2.0f32);
-    assert_approx_eq!(f32::ceil(1.5f32), 2.0f32);
-    assert_approx_eq!(f32::ceil(1.7f32), 2.0f32);
-    assert_approx_eq!(f32::ceil(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::ceil(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::ceil(-1.0f32), -1.0f32);
-    assert_approx_eq!(f32::ceil(-1.3f32), -1.0f32);
-    assert_approx_eq!(f32::ceil(-1.5f32), -1.0f32);
-    assert_approx_eq!(f32::ceil(-1.7f32), -1.0f32);
+    assert_approx_eq!(f32::math::ceil(1.0f32), 1.0f32);
+    assert_approx_eq!(f32::math::ceil(1.3f32), 2.0f32);
+    assert_approx_eq!(f32::math::ceil(1.5f32), 2.0f32);
+    assert_approx_eq!(f32::math::ceil(1.7f32), 2.0f32);
+    assert_approx_eq!(f32::math::ceil(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::ceil(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::ceil(-1.0f32), -1.0f32);
+    assert_approx_eq!(f32::math::ceil(-1.3f32), -1.0f32);
+    assert_approx_eq!(f32::math::ceil(-1.5f32), -1.0f32);
+    assert_approx_eq!(f32::math::ceil(-1.7f32), -1.0f32);
 }
 
 #[test]
 fn test_round() {
-    assert_approx_eq!(f32::round(2.5f32), 3.0f32);
-    assert_approx_eq!(f32::round(1.0f32), 1.0f32);
-    assert_approx_eq!(f32::round(1.3f32), 1.0f32);
-    assert_approx_eq!(f32::round(1.5f32), 2.0f32);
-    assert_approx_eq!(f32::round(1.7f32), 2.0f32);
-    assert_approx_eq!(f32::round(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::round(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::round(-1.0f32), -1.0f32);
-    assert_approx_eq!(f32::round(-1.3f32), -1.0f32);
-    assert_approx_eq!(f32::round(-1.5f32), -2.0f32);
-    assert_approx_eq!(f32::round(-1.7f32), -2.0f32);
+    assert_approx_eq!(f32::math::round(2.5f32), 3.0f32);
+    assert_approx_eq!(f32::math::round(1.0f32), 1.0f32);
+    assert_approx_eq!(f32::math::round(1.3f32), 1.0f32);
+    assert_approx_eq!(f32::math::round(1.5f32), 2.0f32);
+    assert_approx_eq!(f32::math::round(1.7f32), 2.0f32);
+    assert_approx_eq!(f32::math::round(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::round(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::round(-1.0f32), -1.0f32);
+    assert_approx_eq!(f32::math::round(-1.3f32), -1.0f32);
+    assert_approx_eq!(f32::math::round(-1.5f32), -2.0f32);
+    assert_approx_eq!(f32::math::round(-1.7f32), -2.0f32);
 }
 
 #[test]
 fn test_round_ties_even() {
-    assert_approx_eq!(f32::round_ties_even(2.5f32), 2.0f32);
-    assert_approx_eq!(f32::round_ties_even(1.0f32), 1.0f32);
-    assert_approx_eq!(f32::round_ties_even(1.3f32), 1.0f32);
-    assert_approx_eq!(f32::round_ties_even(1.5f32), 2.0f32);
-    assert_approx_eq!(f32::round_ties_even(1.7f32), 2.0f32);
-    assert_approx_eq!(f32::round_ties_even(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::round_ties_even(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::round_ties_even(-1.0f32), -1.0f32);
-    assert_approx_eq!(f32::round_ties_even(-1.3f32), -1.0f32);
-    assert_approx_eq!(f32::round_ties_even(-1.5f32), -2.0f32);
-    assert_approx_eq!(f32::round_ties_even(-1.7f32), -2.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(2.5f32), 2.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(1.0f32), 1.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(1.3f32), 1.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(1.5f32), 2.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(1.7f32), 2.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(-1.0f32), -1.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(-1.3f32), -1.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(-1.5f32), -2.0f32);
+    assert_approx_eq!(f32::math::round_ties_even(-1.7f32), -2.0f32);
 }
 
 #[test]
 fn test_trunc() {
-    assert_approx_eq!(f32::trunc(1.0f32), 1.0f32);
-    assert_approx_eq!(f32::trunc(1.3f32), 1.0f32);
-    assert_approx_eq!(f32::trunc(1.5f32), 1.0f32);
-    assert_approx_eq!(f32::trunc(1.7f32), 1.0f32);
-    assert_approx_eq!(f32::trunc(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::trunc(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::trunc(-1.0f32), -1.0f32);
-    assert_approx_eq!(f32::trunc(-1.3f32), -1.0f32);
-    assert_approx_eq!(f32::trunc(-1.5f32), -1.0f32);
-    assert_approx_eq!(f32::trunc(-1.7f32), -1.0f32);
+    assert_approx_eq!(f32::math::trunc(1.0f32), 1.0f32);
+    assert_approx_eq!(f32::math::trunc(1.3f32), 1.0f32);
+    assert_approx_eq!(f32::math::trunc(1.5f32), 1.0f32);
+    assert_approx_eq!(f32::math::trunc(1.7f32), 1.0f32);
+    assert_approx_eq!(f32::math::trunc(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::trunc(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::trunc(-1.0f32), -1.0f32);
+    assert_approx_eq!(f32::math::trunc(-1.3f32), -1.0f32);
+    assert_approx_eq!(f32::math::trunc(-1.5f32), -1.0f32);
+    assert_approx_eq!(f32::math::trunc(-1.7f32), -1.0f32);
 }
 
 #[test]
 fn test_fract() {
-    assert_approx_eq!(f32::fract(1.0f32), 0.0f32);
-    assert_approx_eq!(f32::fract(1.3f32), 0.3f32);
-    assert_approx_eq!(f32::fract(1.5f32), 0.5f32);
-    assert_approx_eq!(f32::fract(1.7f32), 0.7f32);
-    assert_approx_eq!(f32::fract(0.0f32), 0.0f32);
-    assert_approx_eq!(f32::fract(-0.0f32), -0.0f32);
-    assert_approx_eq!(f32::fract(-1.0f32), -0.0f32);
-    assert_approx_eq!(f32::fract(-1.3f32), -0.3f32);
-    assert_approx_eq!(f32::fract(-1.5f32), -0.5f32);
-    assert_approx_eq!(f32::fract(-1.7f32), -0.7f32);
+    assert_approx_eq!(f32::math::fract(1.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::fract(1.3f32), 0.3f32);
+    assert_approx_eq!(f32::math::fract(1.5f32), 0.5f32);
+    assert_approx_eq!(f32::math::fract(1.7f32), 0.7f32);
+    assert_approx_eq!(f32::math::fract(0.0f32), 0.0f32);
+    assert_approx_eq!(f32::math::fract(-0.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::fract(-1.0f32), -0.0f32);
+    assert_approx_eq!(f32::math::fract(-1.3f32), -0.3f32);
+    assert_approx_eq!(f32::math::fract(-1.5f32), -0.5f32);
+    assert_approx_eq!(f32::math::fract(-1.7f32), -0.7f32);
 }
 
 #[test]
@@ -417,15 +417,15 @@ fn test_mul_add() {
     let nan: f32 = f32::NAN;
     let inf: f32 = f32::INFINITY;
     let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_approx_eq!(f32::mul_add(12.3f32, 4.5, 6.7), 62.05);
-    assert_approx_eq!(f32::mul_add(-12.3f32, -4.5, -6.7), 48.65);
-    assert_approx_eq!(f32::mul_add(0.0f32, 8.9, 1.2), 1.2);
-    assert_approx_eq!(f32::mul_add(3.4f32, -0.0, 5.6), 5.6);
-    assert!(f32::mul_add(nan, 7.8, 9.0).is_nan());
-    assert_eq!(f32::mul_add(inf, 7.8, 9.0), inf);
-    assert_eq!(f32::mul_add(neg_inf, 7.8, 9.0), neg_inf);
-    assert_eq!(f32::mul_add(8.9f32, inf, 3.2), inf);
-    assert_eq!(f32::mul_add(-3.2f32, 2.4, neg_inf), neg_inf);
+    assert_approx_eq!(f32::math::mul_add(12.3f32, 4.5, 6.7), 62.05);
+    assert_approx_eq!(f32::math::mul_add(-12.3f32, -4.5, -6.7), 48.65);
+    assert_approx_eq!(f32::math::mul_add(0.0f32, 8.9, 1.2), 1.2);
+    assert_approx_eq!(f32::math::mul_add(3.4f32, -0.0, 5.6), 5.6);
+    assert!(f32::math::mul_add(nan, 7.8, 9.0).is_nan());
+    assert_eq!(f32::math::mul_add(inf, 7.8, 9.0), inf);
+    assert_eq!(f32::math::mul_add(neg_inf, 7.8, 9.0), neg_inf);
+    assert_eq!(f32::math::mul_add(8.9f32, inf, 3.2), inf);
+    assert_eq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf);
 }
 
 #[test]
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs
index 988108371d7..97051998353 100644
--- a/library/coretests/tests/floats/f64.rs
+++ b/library/coretests/tests/floats/f64.rs
@@ -1,5 +1,6 @@
-use std::f64::consts;
-use std::num::FpCategory as Fp;
+use core::f64;
+use core::f64::consts;
+use core::num::FpCategory as Fp;
 
 /// Smallest number
 const TINY_BITS: u64 = 0x1;
@@ -201,88 +202,88 @@ fn test_classify() {
 
 #[test]
 fn test_floor() {
-    assert_approx_eq!(f64::floor(1.0f64), 1.0f64);
-    assert_approx_eq!(f64::floor(1.3f64), 1.0f64);
-    assert_approx_eq!(f64::floor(1.5f64), 1.0f64);
-    assert_approx_eq!(f64::floor(1.7f64), 1.0f64);
-    assert_approx_eq!(f64::floor(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::floor(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::floor(-1.0f64), -1.0f64);
-    assert_approx_eq!(f64::floor(-1.3f64), -2.0f64);
-    assert_approx_eq!(f64::floor(-1.5f64), -2.0f64);
-    assert_approx_eq!(f64::floor(-1.7f64), -2.0f64);
+    assert_approx_eq!(f64::math::floor(1.0f64), 1.0f64);
+    assert_approx_eq!(f64::math::floor(1.3f64), 1.0f64);
+    assert_approx_eq!(f64::math::floor(1.5f64), 1.0f64);
+    assert_approx_eq!(f64::math::floor(1.7f64), 1.0f64);
+    assert_approx_eq!(f64::math::floor(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::floor(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::floor(-1.0f64), -1.0f64);
+    assert_approx_eq!(f64::math::floor(-1.3f64), -2.0f64);
+    assert_approx_eq!(f64::math::floor(-1.5f64), -2.0f64);
+    assert_approx_eq!(f64::math::floor(-1.7f64), -2.0f64);
 }
 
 #[test]
 fn test_ceil() {
-    assert_approx_eq!(f64::ceil(1.0f64), 1.0f64);
-    assert_approx_eq!(f64::ceil(1.3f64), 2.0f64);
-    assert_approx_eq!(f64::ceil(1.5f64), 2.0f64);
-    assert_approx_eq!(f64::ceil(1.7f64), 2.0f64);
-    assert_approx_eq!(f64::ceil(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::ceil(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::ceil(-1.0f64), -1.0f64);
-    assert_approx_eq!(f64::ceil(-1.3f64), -1.0f64);
-    assert_approx_eq!(f64::ceil(-1.5f64), -1.0f64);
-    assert_approx_eq!(f64::ceil(-1.7f64), -1.0f64);
+    assert_approx_eq!(f64::math::ceil(1.0f64), 1.0f64);
+    assert_approx_eq!(f64::math::ceil(1.3f64), 2.0f64);
+    assert_approx_eq!(f64::math::ceil(1.5f64), 2.0f64);
+    assert_approx_eq!(f64::math::ceil(1.7f64), 2.0f64);
+    assert_approx_eq!(f64::math::ceil(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::ceil(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::ceil(-1.0f64), -1.0f64);
+    assert_approx_eq!(f64::math::ceil(-1.3f64), -1.0f64);
+    assert_approx_eq!(f64::math::ceil(-1.5f64), -1.0f64);
+    assert_approx_eq!(f64::math::ceil(-1.7f64), -1.0f64);
 }
 
 #[test]
 fn test_round() {
-    assert_approx_eq!(f64::round(2.5f64), 3.0f64);
-    assert_approx_eq!(f64::round(1.0f64), 1.0f64);
-    assert_approx_eq!(f64::round(1.3f64), 1.0f64);
-    assert_approx_eq!(f64::round(1.5f64), 2.0f64);
-    assert_approx_eq!(f64::round(1.7f64), 2.0f64);
-    assert_approx_eq!(f64::round(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::round(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::round(-1.0f64), -1.0f64);
-    assert_approx_eq!(f64::round(-1.3f64), -1.0f64);
-    assert_approx_eq!(f64::round(-1.5f64), -2.0f64);
-    assert_approx_eq!(f64::round(-1.7f64), -2.0f64);
+    assert_approx_eq!(f64::math::round(2.5f64), 3.0f64);
+    assert_approx_eq!(f64::math::round(1.0f64), 1.0f64);
+    assert_approx_eq!(f64::math::round(1.3f64), 1.0f64);
+    assert_approx_eq!(f64::math::round(1.5f64), 2.0f64);
+    assert_approx_eq!(f64::math::round(1.7f64), 2.0f64);
+    assert_approx_eq!(f64::math::round(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::round(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::round(-1.0f64), -1.0f64);
+    assert_approx_eq!(f64::math::round(-1.3f64), -1.0f64);
+    assert_approx_eq!(f64::math::round(-1.5f64), -2.0f64);
+    assert_approx_eq!(f64::math::round(-1.7f64), -2.0f64);
 }
 
 #[test]
 fn test_round_ties_even() {
-    assert_approx_eq!(f64::round_ties_even(2.5f64), 2.0f64);
-    assert_approx_eq!(f64::round_ties_even(1.0f64), 1.0f64);
-    assert_approx_eq!(f64::round_ties_even(1.3f64), 1.0f64);
-    assert_approx_eq!(f64::round_ties_even(1.5f64), 2.0f64);
-    assert_approx_eq!(f64::round_ties_even(1.7f64), 2.0f64);
-    assert_approx_eq!(f64::round_ties_even(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::round_ties_even(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::round_ties_even(-1.0f64), -1.0f64);
-    assert_approx_eq!(f64::round_ties_even(-1.3f64), -1.0f64);
-    assert_approx_eq!(f64::round_ties_even(-1.5f64), -2.0f64);
-    assert_approx_eq!(f64::round_ties_even(-1.7f64), -2.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(2.5f64), 2.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(1.0f64), 1.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(1.3f64), 1.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(1.5f64), 2.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(1.7f64), 2.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(-1.0f64), -1.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(-1.3f64), -1.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(-1.5f64), -2.0f64);
+    assert_approx_eq!(f64::math::round_ties_even(-1.7f64), -2.0f64);
 }
 
 #[test]
 fn test_trunc() {
-    assert_approx_eq!(f64::trunc(1.0f64), 1.0f64);
-    assert_approx_eq!(f64::trunc(1.3f64), 1.0f64);
-    assert_approx_eq!(f64::trunc(1.5f64), 1.0f64);
-    assert_approx_eq!(f64::trunc(1.7f64), 1.0f64);
-    assert_approx_eq!(f64::trunc(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::trunc(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::trunc(-1.0f64), -1.0f64);
-    assert_approx_eq!(f64::trunc(-1.3f64), -1.0f64);
-    assert_approx_eq!(f64::trunc(-1.5f64), -1.0f64);
-    assert_approx_eq!(f64::trunc(-1.7f64), -1.0f64);
+    assert_approx_eq!(f64::math::trunc(1.0f64), 1.0f64);
+    assert_approx_eq!(f64::math::trunc(1.3f64), 1.0f64);
+    assert_approx_eq!(f64::math::trunc(1.5f64), 1.0f64);
+    assert_approx_eq!(f64::math::trunc(1.7f64), 1.0f64);
+    assert_approx_eq!(f64::math::trunc(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::trunc(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::trunc(-1.0f64), -1.0f64);
+    assert_approx_eq!(f64::math::trunc(-1.3f64), -1.0f64);
+    assert_approx_eq!(f64::math::trunc(-1.5f64), -1.0f64);
+    assert_approx_eq!(f64::math::trunc(-1.7f64), -1.0f64);
 }
 
 #[test]
 fn test_fract() {
-    assert_approx_eq!(f64::fract(1.0f64), 0.0f64);
-    assert_approx_eq!(f64::fract(1.3f64), 0.3f64);
-    assert_approx_eq!(f64::fract(1.5f64), 0.5f64);
-    assert_approx_eq!(f64::fract(1.7f64), 0.7f64);
-    assert_approx_eq!(f64::fract(0.0f64), 0.0f64);
-    assert_approx_eq!(f64::fract(-0.0f64), -0.0f64);
-    assert_approx_eq!(f64::fract(-1.0f64), -0.0f64);
-    assert_approx_eq!(f64::fract(-1.3f64), -0.3f64);
-    assert_approx_eq!(f64::fract(-1.5f64), -0.5f64);
-    assert_approx_eq!(f64::fract(-1.7f64), -0.7f64);
+    assert_approx_eq!(f64::math::fract(1.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::fract(1.3f64), 0.3f64);
+    assert_approx_eq!(f64::math::fract(1.5f64), 0.5f64);
+    assert_approx_eq!(f64::math::fract(1.7f64), 0.7f64);
+    assert_approx_eq!(f64::math::fract(0.0f64), 0.0f64);
+    assert_approx_eq!(f64::math::fract(-0.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::fract(-1.0f64), -0.0f64);
+    assert_approx_eq!(f64::math::fract(-1.3f64), -0.3f64);
+    assert_approx_eq!(f64::math::fract(-1.5f64), -0.5f64);
+    assert_approx_eq!(f64::math::fract(-1.7f64), -0.7f64);
 }
 
 #[test]
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index b98e52718f6..b1301200981 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -1,6 +1,6 @@
 // tidy-alphabetical-start
 #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
-#![cfg_attr(test, feature(cfg_match))]
+#![cfg_attr(test, feature(cfg_select))]
 #![feature(alloc_layout_extra)]
 #![feature(array_chunks)]
 #![feature(array_ptr_get)]
diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs
index b30a40b7df2..d220e628d73 100644
--- a/library/coretests/tests/macros.rs
+++ b/library/coretests/tests/macros.rs
@@ -9,7 +9,7 @@ trait Trait {
 struct Struct;
 
 impl Trait for Struct {
-    cfg_match! {
+    cfg_select! {
         feature = "blah" => {
             fn blah(&self) {
                 unimplemented!();
@@ -45,22 +45,22 @@ fn matches_leading_pipe() {
 }
 
 #[test]
-fn cfg_match_basic() {
-    cfg_match! {
+fn cfg_select_basic() {
+    cfg_select! {
         target_pointer_width = "64" => { fn f0_() -> bool { true }}
     }
 
-    cfg_match! {
+    cfg_select! {
         unix => { fn f1_() -> bool { true } }
         any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }}
     }
 
-    cfg_match! {
+    cfg_select! {
         target_pointer_width = "32" => { fn f2_() -> bool { false } }
         target_pointer_width = "64" => { fn f2_() -> bool { true } }
     }
 
-    cfg_match! {
+    cfg_select! {
         target_pointer_width = "16" => { fn f3_() -> i32 { 1 } }
         _ => { fn f3_() -> i32 { 2 }}
     }
@@ -81,8 +81,8 @@ fn cfg_match_basic() {
 }
 
 #[test]
-fn cfg_match_debug_assertions() {
-    cfg_match! {
+fn cfg_select_debug_assertions() {
+    cfg_select! {
         debug_assertions => {
             assert!(cfg!(debug_assertions));
             assert_eq!(4, 2+2);
@@ -96,8 +96,8 @@ fn cfg_match_debug_assertions() {
 
 #[cfg(target_pointer_width = "64")]
 #[test]
-fn cfg_match_no_duplication_on_64() {
-    cfg_match! {
+fn cfg_select_no_duplication_on_64() {
+    cfg_select! {
         windows => {
             fn foo() {}
         }
@@ -112,8 +112,8 @@ fn cfg_match_no_duplication_on_64() {
 }
 
 #[test]
-fn cfg_match_options() {
-    cfg_match! {
+fn cfg_select_options() {
+    cfg_select! {
         test => {
             use core::option::Option as Option2;
             fn works1() -> Option2<u32> { Some(1) }
@@ -121,25 +121,25 @@ fn cfg_match_options() {
         _ => { fn works1() -> Option<u32> { None } }
     }
 
-    cfg_match! {
+    cfg_select! {
         feature = "foo" => { fn works2() -> bool { false } }
         test => { fn works2() -> bool { true } }
         _ => { fn works2() -> bool { false } }
     }
 
-    cfg_match! {
+    cfg_select! {
         feature = "foo" => { fn works3() -> bool { false } }
         _ => { fn works3() -> bool { true } }
     }
 
-    cfg_match! {
+    cfg_select! {
         test => {
             use core::option::Option as Option3;
             fn works4() -> Option3<u32> { Some(1) }
         }
     }
 
-    cfg_match! {
+    cfg_select! {
         feature = "foo" => { fn works5() -> bool { false } }
         test => { fn works5() -> bool { true } }
     }
@@ -152,8 +152,8 @@ fn cfg_match_options() {
 }
 
 #[test]
-fn cfg_match_two_functions() {
-    cfg_match! {
+fn cfg_select_two_functions() {
+    cfg_select! {
         target_pointer_width = "64" => {
             fn foo1() {}
             fn bar1() {}
@@ -177,7 +177,7 @@ fn cfg_match_two_functions() {
 }
 
 fn _accepts_expressions() -> i32 {
-    cfg_match! {
+    cfg_select! {
         unix => { 1 }
         _ => { 2 }
     }
@@ -188,14 +188,14 @@ fn _accepts_expressions() -> i32 {
 fn _allows_stmt_expr_attributes() {
     let one = 1;
     let two = 2;
-    cfg_match! {
+    cfg_select! {
         unix => { one * two; }
         _ => { one + two; }
     }
 }
 
 fn _expression() {
-    let _ = cfg_match!({
+    let _ = cfg_select!({
         windows => {
             " XP"
         }
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 94140d01d8b..5210e75ec45 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -46,7 +46,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn floor(self) -> f32 {
-        core::f32::floor(self)
+        core::f32::math::floor(self)
     }
 
     /// Returns the smallest integer greater than or equal to `self`.
@@ -68,7 +68,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ceil(self) -> f32 {
-        core::f32::ceil(self)
+        core::f32::math::ceil(self)
     }
 
     /// Returns the nearest integer to `self`. If a value is half-way between two
@@ -96,7 +96,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn round(self) -> f32 {
-        core::f32::round(self)
+        core::f32::math::round(self)
     }
 
     /// Returns the nearest integer to a number. Rounds half-way cases to the number
@@ -122,7 +122,7 @@ impl f32 {
     #[stable(feature = "round_ties_even", since = "1.77.0")]
     #[inline]
     pub fn round_ties_even(self) -> f32 {
-        core::f32::round_ties_even(self)
+        core::f32::math::round_ties_even(self)
     }
 
     /// Returns the integer part of `self`.
@@ -147,7 +147,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn trunc(self) -> f32 {
-        core::f32::trunc(self)
+        core::f32::math::trunc(self)
     }
 
     /// Returns the fractional part of `self`.
@@ -170,7 +170,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn fract(self) -> f32 {
-        core::f32::fract(self)
+        core::f32::math::fract(self)
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
@@ -212,7 +212,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn mul_add(self, a: f32, b: f32) -> f32 {
-        core::f32::mul_add(self, a, b)
+        core::f32::math::mul_add(self, a, b)
     }
 
     /// Calculates Euclidean division, the matching method for `rem_euclid`.
@@ -242,7 +242,7 @@ impl f32 {
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
     pub fn div_euclid(self, rhs: f32) -> f32 {
-        core::f32::div_euclid(self, rhs)
+        core::f32::math::div_euclid(self, rhs)
     }
 
     /// Calculates the least nonnegative remainder of `self (mod rhs)`.
@@ -279,7 +279,7 @@ impl f32 {
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
     pub fn rem_euclid(self, rhs: f32) -> f32 {
-        core::f32::rem_euclid(self, rhs)
+        core::f32::math::rem_euclid(self, rhs)
     }
 
     /// Raises a number to an integer power.
@@ -307,7 +307,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn powi(self, n: i32) -> f32 {
-        core::f32::powi(self, n)
+        core::f32::math::powi(self, n)
     }
 
     /// Raises a number to a floating point power.
@@ -362,7 +362,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sqrt(self) -> f32 {
-        core::f32::sqrt(self)
+        core::f32::math::sqrt(self)
     }
 
     /// Returns `e^(self)`, (the exponential function).
@@ -595,7 +595,7 @@ impl f32 {
     )]
     pub fn abs_sub(self, other: f32) -> f32 {
         #[allow(deprecated)]
-        core::f32::abs_sub(self, other)
+        core::f32::math::abs_sub(self, other)
     }
 
     /// Returns the cube root of a number.
@@ -622,7 +622,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cbrt(self) -> f32 {
-        core::f32::cbrt(self)
+        core::f32::math::cbrt(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 051061ae605..f837800d663 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -46,7 +46,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn floor(self) -> f64 {
-        core::f64::floor(self)
+        core::f64::math::floor(self)
     }
 
     /// Returns the smallest integer greater than or equal to `self`.
@@ -68,7 +68,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ceil(self) -> f64 {
-        core::f64::ceil(self)
+        core::f64::math::ceil(self)
     }
 
     /// Returns the nearest integer to `self`. If a value is half-way between two
@@ -96,7 +96,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn round(self) -> f64 {
-        core::f64::round(self)
+        core::f64::math::round(self)
     }
 
     /// Returns the nearest integer to a number. Rounds half-way cases to the number
@@ -122,7 +122,7 @@ impl f64 {
     #[stable(feature = "round_ties_even", since = "1.77.0")]
     #[inline]
     pub fn round_ties_even(self) -> f64 {
-        core::f64::round_ties_even(self)
+        core::f64::math::round_ties_even(self)
     }
 
     /// Returns the integer part of `self`.
@@ -147,7 +147,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn trunc(self) -> f64 {
-        core::f64::trunc(self)
+        core::f64::math::trunc(self)
     }
 
     /// Returns the fractional part of `self`.
@@ -170,7 +170,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn fract(self) -> f64 {
-        core::f64::fract(self)
+        core::f64::math::fract(self)
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
@@ -212,7 +212,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn mul_add(self, a: f64, b: f64) -> f64 {
-        core::f64::mul_add(self, a, b)
+        core::f64::math::mul_add(self, a, b)
     }
 
     /// Calculates Euclidean division, the matching method for `rem_euclid`.
@@ -242,7 +242,7 @@ impl f64 {
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
     pub fn div_euclid(self, rhs: f64) -> f64 {
-        core::f64::div_euclid(self, rhs)
+        core::f64::math::div_euclid(self, rhs)
     }
 
     /// Calculates the least nonnegative remainder of `self (mod rhs)`.
@@ -279,7 +279,7 @@ impl f64 {
     #[inline]
     #[stable(feature = "euclidean_division", since = "1.38.0")]
     pub fn rem_euclid(self, rhs: f64) -> f64 {
-        core::f64::rem_euclid(self, rhs)
+        core::f64::math::rem_euclid(self, rhs)
     }
 
     /// Raises a number to an integer power.
@@ -307,7 +307,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn powi(self, n: i32) -> f64 {
-        core::f64::powi(self, n)
+        core::f64::math::powi(self, n)
     }
 
     /// Raises a number to a floating point power.
@@ -362,7 +362,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sqrt(self) -> f64 {
-        core::f64::sqrt(self)
+        core::f64::math::sqrt(self)
     }
 
     /// Returns `e^(self)`, (the exponential function).
@@ -595,7 +595,7 @@ impl f64 {
     )]
     pub fn abs_sub(self, other: f64) -> f64 {
         #[allow(deprecated)]
-        core::f64::abs_sub(self, other)
+        core::f64::math::abs_sub(self, other)
     }
 
     /// Returns the cube root of a number.
@@ -622,7 +622,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cbrt(self) -> f64 {
-        core::f64::cbrt(self)
+        core::f64::math::cbrt(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 56791609910..024cb71b915 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -172,7 +172,7 @@ pub use core::ffi::c_void;
               all supported platforms",
     issue = "44930"
 )]
-pub use core::ffi::{VaList, VaListImpl};
+pub use core::ffi::{VaArgSafe, VaList, VaListImpl};
 #[stable(feature = "core_ffi_c", since = "1.64.0")]
 pub use core::ffi::{
     c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 72bdf03ee61..ead48775127 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -1040,7 +1040,7 @@ impl OsStr {
     /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
     #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
     #[must_use = "`self` will be dropped if the result is not used"]
-    pub fn into_os_string(self: Box<OsStr>) -> OsString {
+    pub fn into_os_string(self: Box<Self>) -> OsString {
         let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
         OsString { inner: Buf::from_box(boxed) }
     }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 11f439b9996..509e673bdb8 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -285,8 +285,7 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
     fn inner(path: &Path) -> io::Result<Vec<u8>> {
         let mut file = File::open(path)?;
         let size = file.metadata().map(|m| m.len() as usize).ok();
-        let mut bytes = Vec::new();
-        bytes.try_reserve_exact(size.unwrap_or(0))?;
+        let mut bytes = Vec::try_with_capacity(size.unwrap_or(0))?;
         io::default_read_to_end(&mut file, &mut bytes, size)?;
         Ok(bytes)
     }
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 96fac4f6bde..03f5f838311 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1214,7 +1214,7 @@ pub trait Read {
     where
         Self: Sized,
     {
-        Take { inner: self, limit }
+        Take { inner: self, len: limit, limit }
     }
 }
 
@@ -2830,6 +2830,7 @@ impl<T, U> SizeHint for Chain<T, U> {
 #[derive(Debug)]
 pub struct Take<T> {
     inner: T,
+    len: u64,
     limit: u64,
 }
 
@@ -2864,6 +2865,12 @@ impl<T> Take<T> {
         self.limit
     }
 
+    /// Returns the number of bytes read so far.
+    #[unstable(feature = "seek_io_take_position", issue = "97227")]
+    pub fn position(&self) -> u64 {
+        self.len - self.limit
+    }
+
     /// Sets the number of bytes that can be read before this instance will
     /// return EOF. This is the same as constructing a new `Take` instance, so
     /// the amount of bytes read and the previous limit value don't matter when
@@ -2889,6 +2896,7 @@ impl<T> Take<T> {
     /// ```
     #[stable(feature = "take_set_limit", since = "1.27.0")]
     pub fn set_limit(&mut self, limit: u64) {
+        self.len = limit;
         self.limit = limit;
     }
 
@@ -3076,6 +3084,49 @@ impl<T> SizeHint for Take<T> {
     }
 }
 
+#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")]
+impl<T: Seek> Seek for Take<T> {
+    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
+        let new_position = match pos {
+            SeekFrom::Start(v) => Some(v),
+            SeekFrom::Current(v) => self.position().checked_add_signed(v),
+            SeekFrom::End(v) => self.len.checked_add_signed(v),
+        };
+        let new_position = match new_position {
+            Some(v) if v <= self.len => v,
+            _ => return Err(ErrorKind::InvalidInput.into()),
+        };
+        while new_position != self.position() {
+            if let Some(offset) = new_position.checked_signed_diff(self.position()) {
+                self.inner.seek_relative(offset)?;
+                self.limit = self.limit.wrapping_sub(offset as u64);
+                break;
+            }
+            let offset = if new_position > self.position() { i64::MAX } else { i64::MIN };
+            self.inner.seek_relative(offset)?;
+            self.limit = self.limit.wrapping_sub(offset as u64);
+        }
+        Ok(new_position)
+    }
+
+    fn stream_len(&mut self) -> Result<u64> {
+        Ok(self.len)
+    }
+
+    fn stream_position(&mut self) -> Result<u64> {
+        Ok(self.position())
+    }
+
+    fn seek_relative(&mut self, offset: i64) -> Result<()> {
+        if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) {
+            return Err(ErrorKind::InvalidInput.into());
+        }
+        self.inner.seek_relative(offset)?;
+        self.limit = self.limit.wrapping_sub(offset as u64);
+        Ok(())
+    }
+}
+
 /// An iterator over `u8` values of a reader.
 ///
 /// This struct is generally created by calling [`bytes`] on a reader.
diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs
index 47243806cd2..16727d44541 100644
--- a/library/std/src/io/pipe.rs
+++ b/library/std/src/io/pipe.rs
@@ -38,30 +38,44 @@ use crate::sys_common::{FromInner, IntoInner};
 /// > not rely on a particular capacity: an application should be designed so that a reading process
 /// > consumes data as soon as it is available, so that a writing process does not remain blocked.
 ///
-/// # Examples
+/// # Example
 ///
 /// ```no_run
 /// # #[cfg(miri)] fn main() {}
 /// # #[cfg(not(miri))]
 /// # fn main() -> std::io::Result<()> {
+/// use std::io::{Read, Write, pipe};
 /// use std::process::Command;
-/// use std::io::{pipe, Read, Write};
-/// let (ping_rx, mut ping_tx) = pipe()?;
-/// let (mut pong_rx, pong_tx) = pipe()?;
+/// let (ping_reader, mut ping_writer) = pipe()?;
+/// let (mut pong_reader, pong_writer) = pipe()?;
 ///
-/// // Spawn a process that echoes its input.
-/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
+/// // Spawn a child process that echoes its input.
+/// let mut echo_command = Command::new("cat");
+/// echo_command.stdin(ping_reader);
+/// echo_command.stdout(pong_writer);
+/// let mut echo_child = echo_command.spawn()?;
 ///
-/// ping_tx.write_all(b"hello")?;
-/// // Close to unblock echo_server's reader.
-/// drop(ping_tx);
+/// // Send input to the child process. Note that because we're writing all the input before we
+/// // read any output, this could deadlock if the child's input and output pipe buffers both
+/// // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer
+/// // inputs we'd need to read and write at the same time, e.g. using threads.
+/// ping_writer.write_all(b"hello")?;
+///
+/// // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer
+/// // remains open. We need to drop our ping writer, or read_to_string will deadlock below.
+/// drop(ping_writer);
+///
+/// // The pong reader can't report EOF while any pong writer remains open. Our Command object is
+/// // holding a pong writer, and again read_to_string will deadlock if we don't drop it.
+/// drop(echo_command);
 ///
 /// let mut buf = String::new();
-/// // Block until echo_server's writer is closed.
-/// pong_rx.read_to_string(&mut buf)?;
+/// // Block until `cat` closes its stdout (a pong writer).
+/// pong_reader.read_to_string(&mut buf)?;
 /// assert_eq!(&buf, "hello");
 ///
-/// echo_server.wait()?;
+/// // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie".
+/// echo_child.wait()?;
 /// # Ok(())
 /// # }
 /// ```
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index fd962b0415c..b22988d4a8a 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -416,6 +416,126 @@ fn seek_position() -> io::Result<()> {
     Ok(())
 }
 
+#[test]
+fn take_seek() -> io::Result<()> {
+    let mut buf = Cursor::new(b"0123456789");
+    buf.set_position(2);
+    let mut take = buf.by_ref().take(4);
+    let mut buf1 = [0u8; 1];
+    let mut buf2 = [0u8; 2];
+    assert_eq!(take.position(), 0);
+
+    assert_eq!(take.seek(SeekFrom::Start(0))?, 0);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'2', b'3']);
+    assert_eq!(take.seek(SeekFrom::Start(1))?, 1);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'3', b'4']);
+    assert_eq!(take.seek(SeekFrom::Start(2))?, 2);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'4', b'5']);
+    assert_eq!(take.seek(SeekFrom::Start(3))?, 3);
+    take.read_exact(&mut buf1)?;
+    assert_eq!(buf1, [b'5']);
+    assert_eq!(take.seek(SeekFrom::Start(4))?, 4);
+    assert_eq!(take.read(&mut buf1)?, 0);
+
+    assert_eq!(take.seek(SeekFrom::End(0))?, 4);
+    assert_eq!(take.seek(SeekFrom::End(-1))?, 3);
+    take.read_exact(&mut buf1)?;
+    assert_eq!(buf1, [b'5']);
+    assert_eq!(take.seek(SeekFrom::End(-2))?, 2);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'4', b'5']);
+    assert_eq!(take.seek(SeekFrom::End(-3))?, 1);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'3', b'4']);
+    assert_eq!(take.seek(SeekFrom::End(-4))?, 0);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'2', b'3']);
+
+    assert_eq!(take.seek(SeekFrom::Current(0))?, 2);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'4', b'5']);
+
+    assert_eq!(take.seek(SeekFrom::Current(-3))?, 1);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'3', b'4']);
+
+    assert_eq!(take.seek(SeekFrom::Current(-1))?, 2);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'4', b'5']);
+
+    assert_eq!(take.seek(SeekFrom::Current(-4))?, 0);
+    take.read_exact(&mut buf2)?;
+    assert_eq!(buf2, [b'2', b'3']);
+
+    assert_eq!(take.seek(SeekFrom::Current(2))?, 4);
+    assert_eq!(take.read(&mut buf1)?, 0);
+
+    Ok(())
+}
+
+#[test]
+fn take_seek_error() {
+    let buf = Cursor::new(b"0123456789");
+    let mut take = buf.take(2);
+    assert!(take.seek(SeekFrom::Start(3)).is_err());
+    assert!(take.seek(SeekFrom::End(1)).is_err());
+    assert!(take.seek(SeekFrom::End(-3)).is_err());
+    assert!(take.seek(SeekFrom::Current(-1)).is_err());
+    assert!(take.seek(SeekFrom::Current(3)).is_err());
+}
+
+struct ExampleHugeRangeOfZeroes {
+    position: u64,
+}
+
+impl Read for ExampleHugeRangeOfZeroes {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let max = buf.len().min(usize::MAX);
+        for i in 0..max {
+            if self.position == u64::MAX {
+                return Ok(i);
+            }
+            self.position += 1;
+            buf[i] = 0;
+        }
+        Ok(max)
+    }
+}
+
+impl Seek for ExampleHugeRangeOfZeroes {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        match pos {
+            io::SeekFrom::Start(i) => self.position = i,
+            io::SeekFrom::End(i) if i >= 0 => self.position = u64::MAX,
+            io::SeekFrom::End(i) => self.position = self.position - i.unsigned_abs(),
+            io::SeekFrom::Current(i) => {
+                self.position = if i >= 0 {
+                    self.position.saturating_add(i.unsigned_abs())
+                } else {
+                    self.position.saturating_sub(i.unsigned_abs())
+                };
+            }
+        }
+        Ok(self.position)
+    }
+}
+
+#[test]
+fn take_seek_big_offsets() -> io::Result<()> {
+    let inner = ExampleHugeRangeOfZeroes { position: 1 };
+    let mut take = inner.take(u64::MAX - 2);
+    assert_eq!(take.seek(io::SeekFrom::Start(u64::MAX - 2))?, u64::MAX - 2);
+    assert_eq!(take.inner.position, u64::MAX - 1);
+    assert_eq!(take.seek(io::SeekFrom::Start(0))?, 0);
+    assert_eq!(take.inner.position, 1);
+    assert_eq!(take.seek(io::SeekFrom::End(-1))?, u64::MAX - 3);
+    assert_eq!(take.inner.position, u64::MAX - 2);
+    Ok(())
+}
+
 // A simple example reader which uses the default implementation of
 // read_to_end.
 struct ExampleSliceReader<'a> {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ca04a381271..4d984617739 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -325,6 +325,7 @@
 #![feature(try_blocks)]
 #![feature(try_trait_v2)]
 #![feature(type_alias_impl_trait)]
+#![feature(unsigned_signed_diff)]
 // tidy-alphabetical-end
 //
 // Library features (core):
@@ -699,8 +700,8 @@ mod panicking;
 #[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
 mod backtrace_rs;
 
-#[unstable(feature = "cfg_match", issue = "115585")]
-pub use core::cfg_match;
+#[unstable(feature = "cfg_select", issue = "115585")]
+pub use core::cfg_select;
 #[unstable(
     feature = "concat_bytes",
     issue = "87555",
diff --git a/library/std/src/os/net/linux_ext/addr.rs b/library/std/src/os/net/linux_ext/addr.rs
index aed772056e1..41009c0e284 100644
--- a/library/std/src/os/net/linux_ext/addr.rs
+++ b/library/std/src/os/net/linux_ext/addr.rs
@@ -23,7 +23,10 @@ pub trait SocketAddrExt: Sealed {
     ///
     /// ```no_run
     /// use std::os::unix::net::{UnixListener, SocketAddr};
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::SocketAddrExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::SocketAddrExt;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let addr = SocketAddr::from_abstract_name(b"hidden")?;
@@ -48,7 +51,10 @@ pub trait SocketAddrExt: Sealed {
     ///
     /// ```no_run
     /// use std::os::unix::net::{UnixListener, SocketAddr};
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::SocketAddrExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::SocketAddrExt;
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let name = b"hidden";
diff --git a/library/std/src/os/net/linux_ext/socket.rs b/library/std/src/os/net/linux_ext/socket.rs
index 4e4168f693c..a15feb6bd9f 100644
--- a/library/std/src/os/net/linux_ext/socket.rs
+++ b/library/std/src/os/net/linux_ext/socket.rs
@@ -27,7 +27,10 @@ pub trait UnixSocketExt: Sealed {
     ///
     /// ```no_run
     /// #![feature(unix_socket_ancillary_data)]
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::UnixSocketExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::UnixSocketExt;
     /// use std::os::unix::net::UnixDatagram;
     ///
     /// fn main() -> std::io::Result<()> {
diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs
index c8d012962d4..95dffb3bc43 100644
--- a/library/std/src/os/net/linux_ext/tcp.rs
+++ b/library/std/src/os/net/linux_ext/tcp.rs
@@ -25,7 +25,10 @@ pub trait TcpStreamExt: Sealed {
     /// ```no_run
     /// #![feature(tcp_quickack)]
     /// use std::net::TcpStream;
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::TcpStreamExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::TcpStreamExt;
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8080")
     ///         .expect("Couldn't connect to the server...");
@@ -43,7 +46,10 @@ pub trait TcpStreamExt: Sealed {
     /// ```no_run
     /// #![feature(tcp_quickack)]
     /// use std::net::TcpStream;
+    /// #[cfg(target_os = "linux")]
     /// use std::os::linux::net::TcpStreamExt;
+    /// #[cfg(target_os = "android")]
+    /// use std::os::android::net::TcpStreamExt;
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8080")
     ///         .expect("Couldn't connect to the server...");
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 7c3fa7d6507..57ce3c5a4bf 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -8,6 +8,7 @@ use cfg_if::cfg_if;
 
 use crate::ffi::OsStr;
 use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::path::Path;
 use crate::sealed::Sealed;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{io, process, sys};
@@ -197,6 +198,18 @@ pub trait CommandExt: Sealed {
     /// ```
     #[stable(feature = "process_set_process_group", since = "1.64.0")]
     fn process_group(&mut self, pgroup: i32) -> &mut process::Command;
+
+    /// Set the root of the child process. This calls `chroot` in the child process before executing
+    /// the command.
+    ///
+    /// This happens before changing to the directory specified with
+    /// [`process::Command::current_dir`], and that directory will be relative to the new root.
+    ///
+    /// If no directory has been specified with [`process::Command::current_dir`], this will set the
+    /// directory to `/`, to avoid leaving the current directory outside the chroot. (This is an
+    /// intentional difference from the underlying `chroot` system call.)
+    #[unstable(feature = "process_chroot", issue = "141298")]
+    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -242,6 +255,11 @@ impl CommandExt for process::Command {
         self.as_inner_mut().pgroup(pgroup);
         self
     }
+
+    fn chroot<P: AsRef<Path>>(&mut self, dir: P) -> &mut process::Command {
+        self.as_inner_mut().chroot(dir.as_ref());
+        self
+    }
 }
 
 /// Unix-specific extensions to [`process::ExitStatus`] and
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 1a4a7aa7448..7959c633858 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3163,7 +3163,7 @@ impl Path {
     /// allocating.
     #[stable(feature = "into_boxed_path", since = "1.20.0")]
     #[must_use = "`self` will be dropped if the result is not used"]
-    pub fn into_path_buf(self: Box<Path>) -> PathBuf {
+    pub fn into_path_buf(self: Box<Self>) -> PathBuf {
         let rw = Box::into_raw(self) as *mut OsStr;
         let inner = unsafe { Box::from_raw(rw) };
         PathBuf { inner: OsString::from(inner) }
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index df6b9a6e563..373584d0117 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1348,7 +1348,7 @@ impl Output {
     ///
     /// ```
     /// #![feature(exit_status_error)]
-    /// # #[cfg(unix)] {
+    /// # #[cfg(all(unix, not(target_os = "android")))] {
     /// use std::process::Command;
     /// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
     /// # }
@@ -1695,7 +1695,7 @@ impl From<io::Stdout> for Stdio {
     /// # Ok(())
     /// # }
     /// #
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// #     test().unwrap();
     /// # }
     /// ```
@@ -1724,7 +1724,7 @@ impl From<io::Stderr> for Stdio {
     /// # Ok(())
     /// # }
     /// #
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// #     test().unwrap();
     /// # }
     /// ```
@@ -1907,7 +1907,7 @@ impl crate::sealed::Sealed for ExitStatusError {}
 ///
 /// ```
 /// #![feature(exit_status_error)]
-/// # if cfg!(unix) {
+/// # if cfg!(all(unix, not(target_os = "android"))) {
 /// use std::process::{Command, ExitStatusError};
 ///
 /// fn run(cmd: &str) -> Result<(), ExitStatusError> {
@@ -1950,7 +1950,7 @@ impl ExitStatusError {
     ///
     /// ```
     /// #![feature(exit_status_error)]
-    /// # #[cfg(unix)] {
+    /// # #[cfg(all(unix, not(target_os = "android")))] {
     /// use std::process::Command;
     ///
     /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
@@ -1975,7 +1975,7 @@ impl ExitStatusError {
     /// ```
     /// #![feature(exit_status_error)]
     ///
-    /// # if cfg!(unix) {
+    /// # if cfg!(all(unix, not(target_os = "android"))) {
     /// use std::num::NonZero;
     /// use std::process::Command;
     ///
@@ -2532,7 +2532,7 @@ pub fn id() -> u32 {
 #[rustc_on_unimplemented(on(
     cause = "MainFunctionType",
     message = "`main` has invalid return type `{Self}`",
-    label = "`main` can only return types that implement `{Termination}`"
+    label = "`main` can only return types that implement `{This}`"
 ))]
 pub trait Termination {
     /// Is called to get the representation of the value as status code.
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
index 3fcfb85cf2a..050f26b097a 100644
--- a/library/std/src/sync/mpmc/list.rs
+++ b/library/std/src/sync/mpmc/list.rs
@@ -575,7 +575,7 @@ impl<T> Channel<T> {
         // After this point `head.block` is not modified again and it will be deallocated if it's
         // non-null. The `Drop` code of the channel, which runs after this function, also attempts
         // to deallocate `head.block` if it's non-null. Therefore this function must maintain the
-        // invariant that if a deallocation of head.block is attemped then it must also be set to
+        // invariant that if a deallocation of head.block is attempted then it must also be set to
         // NULL. Failing to do so will lead to the Drop code attempting a double free. For this
         // reason both reads above do an atomic swap instead of a simple atomic load.
 
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 24539d4e830..96a4cf12659 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -136,7 +136,7 @@ cfg_if!(
             // we only ever read from the tid if `tls_addr` matches the current
             // TLS address. In that case, either the tid has been set by
             // the current thread, or by a thread that has terminated before
-            // the current thread was created. In either case, no further
+            // the current thread's `tls_addr` was allocated. In either case, no further
             // synchronization is needed (as per <https://github.com/rust-lang/miri/issues/3450>)
             tls_addr: Atomic<usize>,
             tid: UnsafeCell<u64>,
@@ -154,8 +154,12 @@ cfg_if!(
             // NOTE: This assumes that `owner` is the ID of the current
             // thread, and may spuriously return `false` if that's not the case.
             fn contains(&self, owner: ThreadId) -> bool {
+                // We must call `tls_addr()` *before* doing the load to ensure that if we reuse an
+                // earlier thread's address, the `tls_addr.load()` below happens-after everything
+                // that thread did.
+                let tls_addr = tls_addr();
                 // SAFETY: See the comments in the struct definition.
-                self.tls_addr.load(Ordering::Relaxed) == tls_addr()
+                self.tls_addr.load(Ordering::Relaxed) == tls_addr
                     && unsafe { *self.tid.get() } == owner.as_u64().get()
             }
 
diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs
index da217439626..46d67c8e510 100644
--- a/library/std/src/sys/net/connection/uefi/mod.rs
+++ b/library/std/src/sys/net/connection/uefi/mod.rs
@@ -4,11 +4,14 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::sys::unsupported;
 use crate::time::Duration;
 
-pub struct TcpStream(!);
+mod tcp;
+pub(crate) mod tcp4;
+
+pub struct TcpStream(#[expect(dead_code)] tcp::Tcp);
 
 impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        unsupported()
+    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        tcp::Tcp::connect(addr?).map(Self)
     }
 
     pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
@@ -16,105 +19,105 @@ impl TcpStream {
     }
 
     pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
+        unsupported()
     }
 
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0
+        unsupported()
     }
 
     pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
+        unsupported()
     }
 
     pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        self.0
+        unsupported()
     }
 
     pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0
+        unsupported()
     }
 
     pub fn is_read_vectored(&self) -> bool {
-        self.0
+        false
     }
 
     pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        self.0
+        unsupported()
     }
 
     pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0
+        unsupported()
     }
 
     pub fn is_write_vectored(&self) -> bool {
-        self.0
+        false
     }
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        self.0
+        unsupported()
     }
 
     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        self.0
+        unsupported()
     }
 
     pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn duplicate(&self) -> io::Result<TcpStream> {
-        self.0
+        unsupported()
     }
 
     pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn linger(&self) -> io::Result<Option<Duration>> {
-        self.0
+        unsupported()
     }
 
     pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn nodelay(&self) -> io::Result<bool> {
-        self.0
+        unsupported()
     }
 
     pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 
     pub fn ttl(&self) -> io::Result<u32> {
-        self.0
+        unsupported()
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0
+        unsupported()
     }
 
     pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        self.0
+        unsupported()
     }
 }
 
 impl fmt::Debug for TcpStream {
     fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
+        todo!()
     }
 }
 
diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs
new file mode 100644
index 00000000000..f87accdc41d
--- /dev/null
+++ b/library/std/src/sys/net/connection/uefi/tcp.rs
@@ -0,0 +1,21 @@
+use super::tcp4;
+use crate::io;
+use crate::net::SocketAddr;
+
+pub(crate) enum Tcp {
+    V4(#[expect(dead_code)] tcp4::Tcp4),
+}
+
+impl Tcp {
+    pub(crate) fn connect(addr: &SocketAddr) -> io::Result<Self> {
+        match addr {
+            SocketAddr::V4(x) => {
+                let temp = tcp4::Tcp4::new()?;
+                temp.configure(true, Some(x), None)?;
+                temp.connect()?;
+                Ok(Tcp::V4(temp))
+            }
+            SocketAddr::V6(_) => todo!(),
+        }
+    }
+}
diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs
new file mode 100644
index 00000000000..f7ca373b52b
--- /dev/null
+++ b/library/std/src/sys/net/connection/uefi/tcp4.rs
@@ -0,0 +1,118 @@
+use r_efi::efi::{self, Status};
+use r_efi::protocols::tcp4;
+
+use crate::io;
+use crate::net::SocketAddrV4;
+use crate::ptr::NonNull;
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sys::pal::helpers;
+
+const TYPE_OF_SERVICE: u8 = 8;
+const TIME_TO_LIVE: u8 = 255;
+
+pub(crate) struct Tcp4 {
+    protocol: NonNull<tcp4::Protocol>,
+    flag: AtomicBool,
+    #[expect(dead_code)]
+    service_binding: helpers::ServiceProtocol,
+}
+
+const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] };
+
+impl Tcp4 {
+    pub(crate) fn new() -> io::Result<Self> {
+        let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
+        let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?;
+
+        Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) })
+    }
+
+    pub(crate) fn configure(
+        &self,
+        active: bool,
+        remote_address: Option<&SocketAddrV4>,
+        station_address: Option<&SocketAddrV4>,
+    ) -> io::Result<()> {
+        let protocol = self.protocol.as_ptr();
+
+        let (remote_address, remote_port) = if let Some(x) = remote_address {
+            (helpers::ipv4_to_r_efi(*x.ip()), x.port())
+        } else {
+            (DEFAULT_ADDR, 0)
+        };
+
+        // FIXME: Remove when passive connections with proper subnet handling are added
+        assert!(station_address.is_none());
+        let use_default_address = efi::Boolean::TRUE;
+        let (station_address, station_port) = (DEFAULT_ADDR, 0);
+        let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0));
+
+        let mut config_data = tcp4::ConfigData {
+            type_of_service: TYPE_OF_SERVICE,
+            time_to_live: TIME_TO_LIVE,
+            access_point: tcp4::AccessPoint {
+                use_default_address,
+                remote_address,
+                remote_port,
+                active_flag: active.into(),
+                station_address,
+                station_port,
+                subnet_mask,
+            },
+            control_option: crate::ptr::null_mut(),
+        };
+
+        let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) };
+        if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+    }
+
+    pub(crate) fn connect(&self) -> io::Result<()> {
+        let evt = unsafe { self.create_evt() }?;
+        let completion_token =
+            tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
+
+        let protocol = self.protocol.as_ptr();
+        let mut conn_token = tcp4::ConnectionToken { completion_token };
+
+        let r = unsafe { ((*protocol).connect)(protocol, &mut conn_token) };
+        if r.is_error() {
+            return Err(io::Error::from_raw_os_error(r.as_usize()));
+        }
+
+        self.wait_for_flag();
+
+        if completion_token.status.is_error() {
+            Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
+        } else {
+            Ok(())
+        }
+    }
+
+    unsafe fn create_evt(&self) -> io::Result<helpers::OwnedEvent> {
+        self.flag.store(false, Ordering::Relaxed);
+        helpers::OwnedEvent::new(
+            efi::EVT_NOTIFY_SIGNAL,
+            efi::TPL_CALLBACK,
+            Some(toggle_atomic_flag),
+            Some(unsafe { NonNull::new_unchecked(self.flag.as_ptr().cast()) }),
+        )
+    }
+
+    fn wait_for_flag(&self) {
+        while !self.flag.load(Ordering::Relaxed) {
+            let _ = self.poll();
+        }
+    }
+
+    fn poll(&self) -> io::Result<()> {
+        let protocol = self.protocol.as_ptr();
+        let r = unsafe { ((*protocol).poll)(protocol) };
+
+        if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+    }
+}
+
+extern "efiapi" fn toggle_atomic_flag(_: r_efi::efi::Event, ctx: *mut crate::ffi::c_void) {
+    let flag = unsafe { AtomicBool::from_ptr(ctx.cast()) };
+    flag.store(true, Ordering::Relaxed);
+}
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 6ee3e0a8b66..e47263348db 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -653,7 +653,6 @@ pub(crate) struct ServiceProtocol {
 }
 
 impl ServiceProtocol {
-    #[expect(dead_code)]
     pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result<Self> {
         let handles = locate_handles(service_guid)?;
 
@@ -670,7 +669,6 @@ impl ServiceProtocol {
         Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found"))
     }
 
-    #[expect(dead_code)]
     pub(crate) fn child_handle(&self) -> NonNull<crate::ffi::c_void> {
         self.child_handle
     }
@@ -732,6 +730,10 @@ impl OwnedEvent {
         }
     }
 
+    pub(crate) fn as_ptr(&self) -> efi::Event {
+        self.0.as_ptr()
+    }
+
     pub(crate) fn into_raw(self) -> *mut crate::ffi::c_void {
         let r = self.0.as_ptr();
         crate::mem::forget(self);
@@ -755,3 +757,7 @@ impl Drop for OwnedEvent {
         }
     }
 }
+
+pub(crate) const fn ipv4_to_r_efi(addr: crate::net::Ipv4Addr) -> efi::Ipv4Address {
+    efi::Ipv4Address { addr: addr.octets() }
+}
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index a9c2510e6d4..b6777b76668 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -1,8 +1,10 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_char, c_int, gid_t, pid_t, uid_t};
+use libc::{EXIT_FAILURE, EXIT_SUCCESS, c_int, gid_t, pid_t, uid_t};
 
+pub use self::cstring_array::CStringArray;
+use self::cstring_array::CStringIter;
 use crate::collections::BTreeMap;
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::os::unix::prelude::*;
@@ -14,7 +16,9 @@ use crate::sys::fs::OpenOptions;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::process::env::{CommandEnv, CommandEnvs};
 use crate::sys_common::{FromInner, IntoInner};
-use crate::{fmt, io, ptr};
+use crate::{fmt, io};
+
+mod cstring_array;
 
 cfg_if::cfg_if! {
     if #[cfg(target_os = "fuchsia")] {
@@ -77,17 +81,12 @@ cfg_if::cfg_if! {
 
 pub struct Command {
     program: CString,
-    args: Vec<CString>,
-    /// Exactly what will be passed to `execvp`.
-    ///
-    /// First element is a pointer to `program`, followed by pointers to
-    /// `args`, followed by a `null`. Be careful when modifying `program` or
-    /// `args` to properly update this as well.
-    argv: Argv,
+    args: CStringArray,
     env: CommandEnv,
 
     program_kind: ProgramKind,
     cwd: Option<CString>,
+    chroot: Option<CString>,
     uid: Option<uid_t>,
     gid: Option<gid_t>,
     saw_nul: bool,
@@ -101,14 +100,6 @@ pub struct Command {
     pgroup: Option<pid_t>,
 }
 
-// Create a new type for argv, so that we can make it `Send` and `Sync`
-struct Argv(Vec<*const c_char>);
-
-// It is safe to make `Argv` `Send` and `Sync`, because it contains
-// pointers to memory owned by `Command.args`
-unsafe impl Send for Argv {}
-unsafe impl Sync for Argv {}
-
 // passed back to std::process with the pipes connected to the child, if any
 // were requested
 pub struct StdioPipes {
@@ -170,42 +161,19 @@ impl ProgramKind {
 }
 
 impl Command {
-    #[cfg(not(target_os = "linux"))]
     pub fn new(program: &OsStr) -> Command {
         let mut saw_nul = false;
         let program_kind = ProgramKind::new(program.as_ref());
         let program = os2c(program, &mut saw_nul);
+        let mut args = CStringArray::with_capacity(1);
+        args.push(program.clone());
         Command {
-            argv: Argv(vec![program.as_ptr(), ptr::null()]),
-            args: vec![program.clone()],
             program,
-            program_kind,
+            args,
             env: Default::default(),
-            cwd: None,
-            uid: None,
-            gid: None,
-            saw_nul,
-            closures: Vec::new(),
-            groups: None,
-            stdin: None,
-            stdout: None,
-            stderr: None,
-            pgroup: None,
-        }
-    }
-
-    #[cfg(target_os = "linux")]
-    pub fn new(program: &OsStr) -> Command {
-        let mut saw_nul = false;
-        let program_kind = ProgramKind::new(program.as_ref());
-        let program = os2c(program, &mut saw_nul);
-        Command {
-            argv: Argv(vec![program.as_ptr(), ptr::null()]),
-            args: vec![program.clone()],
-            program,
             program_kind,
-            env: Default::default(),
             cwd: None,
+            chroot: None,
             uid: None,
             gid: None,
             saw_nul,
@@ -214,6 +182,7 @@ impl Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            #[cfg(target_os = "linux")]
             create_pidfd: false,
             pgroup: None,
         }
@@ -222,20 +191,11 @@ impl Command {
     pub fn set_arg_0(&mut self, arg: &OsStr) {
         // Set a new arg0
         let arg = os2c(arg, &mut self.saw_nul);
-        debug_assert!(self.argv.0.len() > 1);
-        self.argv.0[0] = arg.as_ptr();
-        self.args[0] = arg;
+        self.args.write(0, arg);
     }
 
     pub fn arg(&mut self, arg: &OsStr) {
-        // Overwrite the trailing null pointer in `argv` and then add a new null
-        // pointer.
         let arg = os2c(arg, &mut self.saw_nul);
-        self.argv.0[self.args.len()] = arg.as_ptr();
-        self.argv.0.push(ptr::null());
-
-        // Also make sure we keep track of the owned value to schedule a
-        // destructor for this memory.
         self.args.push(arg);
     }
 
@@ -254,6 +214,12 @@ impl Command {
     pub fn pgroup(&mut self, pgroup: pid_t) {
         self.pgroup = Some(pgroup);
     }
+    pub fn chroot(&mut self, dir: &Path) {
+        self.chroot = Some(os2c(dir.as_os_str(), &mut self.saw_nul));
+        if self.cwd.is_none() {
+            self.cwd(&OsStr::new("/"));
+        }
+    }
 
     #[cfg(target_os = "linux")]
     pub fn create_pidfd(&mut self, val: bool) {
@@ -286,6 +252,8 @@ impl Command {
 
     pub fn get_args(&self) -> CommandArgs<'_> {
         let mut iter = self.args.iter();
+        // argv[0] contains the program name, but we are only interested in the
+        // arguments so skip it.
         iter.next();
         CommandArgs { iter }
     }
@@ -298,12 +266,12 @@ impl Command {
         self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
     }
 
-    pub fn get_argv(&self) -> &Vec<*const c_char> {
-        &self.argv.0
+    pub fn get_argv(&self) -> &CStringArray {
+        &self.args
     }
 
     pub fn get_program_cstr(&self) -> &CStr {
-        &*self.program
+        &self.program
     }
 
     #[allow(dead_code)]
@@ -326,6 +294,10 @@ impl Command {
     pub fn get_pgroup(&self) -> Option<pid_t> {
         self.pgroup
     }
+    #[allow(dead_code)]
+    pub fn get_chroot(&self) -> Option<&CStr> {
+        self.chroot.as_deref()
+    }
 
     pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
@@ -392,32 +364,6 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
     })
 }
 
-// Helper type to manage ownership of the strings within a C-style array.
-pub struct CStringArray {
-    items: Vec<CString>,
-    ptrs: Vec<*const c_char>,
-}
-
-impl CStringArray {
-    pub fn with_capacity(capacity: usize) -> Self {
-        let mut result = CStringArray {
-            items: Vec::with_capacity(capacity),
-            ptrs: Vec::with_capacity(capacity + 1),
-        };
-        result.ptrs.push(ptr::null());
-        result
-    }
-    pub fn push(&mut self, item: CString) {
-        let l = self.ptrs.len();
-        self.ptrs[l - 1] = item.as_ptr();
-        self.ptrs.push(ptr::null());
-        self.items.push(item);
-    }
-    pub fn as_ptr(&self) -> *const *const c_char {
-        self.ptrs.as_ptr()
-    }
-}
-
 fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
     let mut result = CStringArray::with_capacity(env.len());
     for (mut k, v) in env {
@@ -606,14 +552,16 @@ impl fmt::Debug for Command {
                     write!(f, "{}={value:?} ", key.to_string_lossy())?;
                 }
             }
-            if self.program != self.args[0] {
+
+            if *self.program != self.args[0] {
                 write!(f, "[{:?}] ", self.program)?;
             }
-            write!(f, "{:?}", self.args[0])?;
+            write!(f, "{:?}", &self.args[0])?;
 
-            for arg in &self.args[1..] {
+            for arg in self.get_args() {
                 write!(f, " {:?}", arg)?;
             }
+
             Ok(())
         }
     }
@@ -645,14 +593,16 @@ impl From<u8> for ExitCode {
 }
 
 pub struct CommandArgs<'a> {
-    iter: crate::slice::Iter<'a, CString>,
+    iter: CStringIter<'a>,
 }
 
 impl<'a> Iterator for CommandArgs<'a> {
     type Item = &'a OsStr;
+
     fn next(&mut self) -> Option<&'a OsStr> {
-        self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes()))
+        self.iter.next().map(|cs| OsStr::from_bytes(cs.to_bytes()))
     }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
@@ -662,6 +612,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
     fn len(&self) -> usize {
         self.iter.len()
     }
+
     fn is_empty(&self) -> bool {
         self.iter.is_empty()
     }
diff --git a/library/std/src/sys/process/unix/common/cstring_array.rs b/library/std/src/sys/process/unix/common/cstring_array.rs
new file mode 100644
index 00000000000..1c840a85df9
--- /dev/null
+++ b/library/std/src/sys/process/unix/common/cstring_array.rs
@@ -0,0 +1,115 @@
+use crate::ffi::{CStr, CString, c_char};
+use crate::ops::Index;
+use crate::{fmt, mem, ptr};
+
+/// Helper type to manage ownership of the strings within a C-style array.
+///
+/// This type manages an array of C-string pointers terminated by a null
+/// pointer. The pointer to the array (as returned by `as_ptr`) can be used as
+/// a value of `argv` or `environ`.
+pub struct CStringArray {
+    ptrs: Vec<*const c_char>,
+}
+
+impl CStringArray {
+    /// Creates a new `CStringArray` with enough capacity to hold `capacity`
+    /// strings.
+    pub fn with_capacity(capacity: usize) -> Self {
+        let mut result = CStringArray { ptrs: Vec::with_capacity(capacity + 1) };
+        result.ptrs.push(ptr::null());
+        result
+    }
+
+    /// Replace the string at position `index`.
+    pub fn write(&mut self, index: usize, item: CString) {
+        let argc = self.ptrs.len() - 1;
+        let ptr = &mut self.ptrs[..argc][index];
+        let old = mem::replace(ptr, item.into_raw());
+        // SAFETY:
+        // `CStringArray` owns all of its strings, and they were all transformed
+        // into pointers using `CString::into_raw`. Also, this is not the null
+        // pointer since the indexing above would have failed.
+        drop(unsafe { CString::from_raw(old.cast_mut()) });
+    }
+
+    /// Push an additional string to the array.
+    pub fn push(&mut self, item: CString) {
+        let argc = self.ptrs.len() - 1;
+        // Replace the null pointer at the end of the array...
+        self.ptrs[argc] = item.into_raw();
+        // ... and recreate it to restore the data structure invariant.
+        self.ptrs.push(ptr::null());
+    }
+
+    /// Returns a pointer to the C-string array managed by this type.
+    pub fn as_ptr(&self) -> *const *const c_char {
+        self.ptrs.as_ptr()
+    }
+
+    /// Returns an iterator over all `CStr`s contained in this array.
+    pub fn iter(&self) -> CStringIter<'_> {
+        CStringIter { iter: self.ptrs[..self.ptrs.len() - 1].iter() }
+    }
+}
+
+impl Index<usize> for CStringArray {
+    type Output = CStr;
+    fn index(&self, index: usize) -> &CStr {
+        let ptr = self.ptrs[..self.ptrs.len() - 1][index];
+        // SAFETY:
+        // `CStringArray` owns all of its strings. Also, this is not the null
+        // pointer since the indexing above would have failed.
+        unsafe { CStr::from_ptr(ptr) }
+    }
+}
+
+impl fmt::Debug for CStringArray {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter()).finish()
+    }
+}
+
+// SAFETY: `CStringArray` is basically just a `Vec<CString>`
+unsafe impl Send for CStringArray {}
+// SAFETY: `CStringArray` is basically just a `Vec<CString>`
+unsafe impl Sync for CStringArray {}
+
+impl Drop for CStringArray {
+    fn drop(&mut self) {
+        // SAFETY:
+        // `CStringArray` owns all of its strings, and they were all transformed
+        // into pointers using `CString::into_raw`.
+        self.ptrs[..self.ptrs.len() - 1]
+            .iter()
+            .for_each(|&p| drop(unsafe { CString::from_raw(p.cast_mut()) }))
+    }
+}
+
+/// An iterator over all `CStr`s contained in a `CStringArray`.
+#[derive(Clone)]
+pub struct CStringIter<'a> {
+    iter: crate::slice::Iter<'a, *const c_char>,
+}
+
+impl<'a> Iterator for CStringIter<'a> {
+    type Item = &'a CStr;
+    fn next(&mut self) -> Option<&'a CStr> {
+        // SAFETY:
+        // `CStringArray` owns all of its strings. Also, this is not the null
+        // pointer since the last element is excluded when creating `iter`.
+        self.iter.next().map(|&p| unsafe { CStr::from_ptr(p) })
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for CStringIter<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 1b3bd2de265..4f595ac9a1c 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -323,6 +323,15 @@ impl Command {
                 cvt(libc::setuid(u as uid_t))?;
             }
         }
+        if let Some(chroot) = self.get_chroot() {
+            #[cfg(not(target_os = "fuchsia"))]
+            cvt(libc::chroot(chroot.as_ptr()))?;
+            #[cfg(target_os = "fuchsia")]
+            return Err(io::const_error!(
+                io::ErrorKind::Unsupported,
+                "chroot not supported by fuchsia"
+            ));
+        }
         if let Some(cwd) = self.get_cwd() {
             cvt(libc::chdir(cwd.as_ptr()))?;
         }
@@ -447,6 +456,7 @@ impl Command {
             || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
             || self.get_groups().is_some()
+            || self.get_chroot().is_some()
         {
             return Ok(None);
         }
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index fab3b36ebf3..f33b4a375da 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -27,6 +27,12 @@ impl Command {
                 "nul byte found in provided data",
             ));
         }
+        if self.get_chroot().is_some() {
+            return Err(io::const_error!(
+                ErrorKind::Unsupported,
+                "chroot not supported by vxworks",
+            ));
+        }
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
         let mut p = Process { pid: 0, status: None };
 
diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs
index 59581e6f281..f91471419c1 100644
--- a/library/std/src/sys/thread_local/guard/key.rs
+++ b/library/std/src/sys/thread_local/guard/key.rs
@@ -32,7 +32,7 @@ pub fn enable() {
 
 /// On platforms with key-based TLS, the system runs the destructors for us.
 /// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
-/// however. This is done by defering the execution of a TLS destructor to
+/// however. This is done by deferring the execution of a TLS destructor to
 /// the next round of destruction inside the TLS destructors.
 #[cfg(not(target_thread_local))]
 pub fn enable() {
@@ -46,7 +46,7 @@ pub fn enable() {
     unsafe extern "C" fn run(state: *mut u8) {
         if state == DEFER {
             // Make sure that this function is run again in the next round of
-            // TLS destruction. If there is no futher round, there will be leaks,
+            // TLS destruction. If there is no further round, there will be leaks,
             // but that's okay, `thread_cleanup` is not guaranteed to be called.
             unsafe { set(CLEANUP.force(), RUN) }
         } else {
diff --git a/library/stdarch b/library/stdarch
-Subproject 1dfaa4db2479753a46a3e90f2c3c89d89d0b21f
+Subproject b6e2249e388f520627544812649b77b0944e1a2
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index d10d2d9bf8c..0c8e6633560 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -89,9 +89,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
 dependencies = [
  "shlex",
 ]
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 9652d18f1a6..b12b3dfc7b2 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -32,7 +32,7 @@ test = false
 # Most of the time updating these dependencies requires modifications to the
 # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
 # otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
-cc = "=1.2.17"
+cc = "=1.2.23"
 cmake = "=0.1.54"
 
 build_helper = { path = "../build_helper" }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 67daf81ee54..d5ea96b43f5 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1984,17 +1984,20 @@ impl Step for Assemble {
                     trace!("installing `{tool}`");
                     let tool_exe = exe(tool, target_compiler.host);
                     let src_path = llvm_bin_dir.join(&tool_exe);
-                    // When using `download-ci-llvm`, some of the tools
-                    // may not exist, so skip trying to copy them.
-                    if src_path.exists() {
-                        // There is a chance that these tools are being installed from an external LLVM.
-                        // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
-                        // we are copying the original file not the symlinked path, which causes issues for
-                        // tarball distribution.
-                        //
-                        // See https://github.com/rust-lang/rust/issues/135554.
-                        builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
+
+                    // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+                    if !src_path.exists() && builder.config.llvm_from_ci {
+                        eprintln!("{} does not exist; skipping copy", src_path.display());
+                        continue;
                     }
+
+                    // There is a chance that these tools are being installed from an external LLVM.
+                    // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
+                    // we are copying the original file not the symlinked path, which causes issues for
+                    // tarball distribution.
+                    //
+                    // See https://github.com/rust-lang/rust/issues/135554.
+                    builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
                 }
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index aa2c7509c2a..253fa224152 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2274,9 +2274,9 @@ impl Step for LlvmTools {
 
         let target = self.target;
 
-        /* run only if llvm-config isn't used */
+        // Run only if a custom llvm-config is not used
         if let Some(config) = builder.config.target_config.get(&target) {
-            if let Some(ref _s) = config.llvm_config {
+            if !builder.config.llvm_from_ci && config.llvm_config.is_some() {
                 builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
                 return None;
             }
@@ -2294,6 +2294,12 @@ impl Step for LlvmTools {
             let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
             for tool in tools_to_install(&builder.paths) {
                 let exe = src_bindir.join(exe(tool, target));
+                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+                if !exe.exists() && builder.config.llvm_from_ci {
+                    eprintln!("{} does not exist; skipping copy", exe.display());
+                    continue;
+                }
+
                 tarball.add_file(&exe, &dst_bindir, FileType::Executable);
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index c31c40e846b..585adf9be16 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -244,7 +244,7 @@ install!((self, builder, _config),
             );
         }
     };
-    LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
+    LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
             install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
         } else {
diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs
index 7f4e88bd73c..71cdb665ed4 100644
--- a/src/bootstrap/src/core/build_steps/perf.rs
+++ b/src/bootstrap/src/core/build_steps/perf.rs
@@ -1,3 +1,4 @@
+use std::env::consts::EXE_EXTENSION;
 use std::fmt::{Display, Formatter};
 
 use crate::core::build_steps::compile::{Std, Sysroot};
@@ -160,7 +161,10 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#);
     }
 
     let sysroot = builder.ensure(Sysroot::new(compiler));
-    let rustc = sysroot.join("bin/rustc");
+    let mut rustc = sysroot.clone();
+    rustc.push("bin");
+    rustc.push("rustc");
+    rustc.set_extension(EXE_EXTENSION);
 
     let rustc_perf_dir = builder.build.tempdir().join("rustc-perf");
     let results_dir = rustc_perf_dir.join("results");
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 31ec462134d..5e22c2d1acb 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -585,11 +585,13 @@ Select which editor you would like to set up [default: None]: ";
                 "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
                 "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
                 "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
+                "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
             ],
             EditorKind::Helix => &[
                 "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
                 "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
                 "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
+                "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
             ],
             EditorKind::Vim | EditorKind::VsCode => &[
                 "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
@@ -604,11 +606,13 @@ Select which editor you would like to set up [default: None]: ";
                 "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
                 "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
                 "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+                "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
             ],
             EditorKind::Zed => &[
                 "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
                 "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
                 "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
+                "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
             ],
         }
     }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index eb7e3799a68..af4ec679d08 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -13,7 +13,6 @@ use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
 use std::{env, fs};
 
-use crate::Build;
 #[cfg(not(test))]
 use crate::builder::Builder;
 use crate::builder::Kind;
@@ -21,6 +20,7 @@ use crate::builder::Kind;
 use crate::core::build_steps::tool;
 use crate::core::config::Target;
 use crate::utils::exec::command;
+use crate::{Build, Subcommand};
 
 pub struct Finder {
     cache: HashMap<OsString, Option<PathBuf>>,
@@ -205,6 +205,20 @@ than building it.
     .map(|s| s.to_string())
     .collect();
 
+    // Compiler tools like `cc` and `ar` are not configured for cross-targets on certain subcommands
+    // because they are not needed.
+    //
+    // See `cc_detect::find` for more details.
+    let skip_tools_checks = build.config.dry_run()
+        || matches!(
+            build.config.cmd,
+            Subcommand::Clean { .. }
+                | Subcommand::Check { .. }
+                | Subcommand::Suggest { .. }
+                | Subcommand::Format { .. }
+                | Subcommand::Setup { .. }
+        );
+
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in &build.targets {
@@ -278,7 +292,7 @@ than building it.
             }
         }
 
-        if !build.config.dry_run() {
+        if !skip_tools_checks {
             cmd_finder.must_have(build.cc(*target));
             if let Some(ar) = build.ar(*target) {
                 cmd_finder.must_have(ar);
@@ -286,7 +300,7 @@ than building it.
         }
     }
 
-    if !build.config.dry_run() {
+    if !skip_tools_checks {
         for host in &build.hosts {
             cmd_finder.must_have(build.cxx(*host).unwrap());
 
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index 1c8cc4025df..46eeffad88c 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -20,7 +20,6 @@ use std::collections::HashMap;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::ops::Deref;
-use std::path::PathBuf;
 use std::sync::{LazyLock, Mutex};
 use std::{fmt, mem};
 
@@ -51,26 +50,11 @@ impl<T> PartialEq for Interned<T> {
 }
 impl<T> Eq for Interned<T> {}
 
-impl PartialEq<str> for Interned<String> {
-    fn eq(&self, other: &str) -> bool {
-        *self == other
-    }
-}
 impl PartialEq<&str> for Interned<String> {
     fn eq(&self, other: &&str) -> bool {
         **self == **other
     }
 }
-impl<T> PartialEq<&Interned<T>> for Interned<T> {
-    fn eq(&self, other: &&Self) -> bool {
-        self.0 == other.0
-    }
-}
-impl<T> PartialEq<Interned<T>> for &Interned<T> {
-    fn eq(&self, other: &Interned<T>) -> bool {
-        self.0 == other.0
-    }
-}
 
 unsafe impl<T> Send for Interned<T> {}
 unsafe impl<T> Sync for Interned<T> {}
@@ -188,8 +172,6 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
 #[derive(Default)]
 pub struct Interner {
     strs: Mutex<TyIntern<String>>,
-    paths: Mutex<TyIntern<PathBuf>>,
-    lists: Mutex<TyIntern<Vec<String>>>,
 }
 
 /// Defines the behavior required for a type to be internable.
@@ -210,18 +192,6 @@ impl Internable for String {
     }
 }
 
-impl Internable for PathBuf {
-    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
-        &INTERNER.paths
-    }
-}
-
-impl Internable for Vec<String> {
-    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
-        &INTERNER.lists
-    }
-}
-
 impl Interner {
     /// Interns a string reference, ensuring it is stored uniquely.
     ///
diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs
index 28f5563a589..8562a35b3e0 100644
--- a/src/bootstrap/src/utils/cache/tests.rs
+++ b/src/bootstrap/src/utils/cache/tests.rs
@@ -13,26 +13,6 @@ fn test_string_interning() {
 }
 
 #[test]
-fn test_path_interning() {
-    let p1 = PathBuf::from("/tmp/file").intern();
-    let p2 = PathBuf::from("/tmp/file").intern();
-    let p3 = PathBuf::from("/tmp/other").intern();
-
-    assert_eq!(p1, p2);
-    assert_ne!(p1, p3);
-}
-
-#[test]
-fn test_vec_interning() {
-    let v1 = vec!["a".to_string(), "b".to_string()].intern();
-    let v2 = vec!["a".to_string(), "b".to_string()].intern();
-    let v3 = vec!["c".to_string()].intern();
-
-    assert_eq!(v1, v2);
-    assert_ne!(v1, v3);
-}
-
-#[test]
 fn test_interned_equality() {
     let s1 = INTERNER.intern_str("test");
     let s2 = INTERNER.intern_str("test");
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index ceac24d4315..5c9e30706ee 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -22,43 +22,13 @@
 //! everything.
 
 use std::collections::HashSet;
+use std::iter;
 use std::path::{Path, PathBuf};
-use std::{env, iter};
 
 use crate::core::config::TargetSelection;
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::{Build, CLang, GitRepo};
 
-/// Finds archiver tool for the given target if possible.
-/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate.
-fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option<PathBuf> {
-    if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) {
-        Some(PathBuf::from(ar))
-    } else if let Some(ar) = env::var_os("AR") {
-        Some(PathBuf::from(ar))
-    } else if target.is_msvc() {
-        None
-    } else if target.contains("musl") || target.contains("openbsd") {
-        Some(PathBuf::from("ar"))
-    } else if target.contains("vxworks") {
-        Some(PathBuf::from("wr-ar"))
-    } else if target.contains("-nto-") {
-        if target.starts_with("i586") {
-            Some(PathBuf::from("ntox86-ar"))
-        } else if target.starts_with("aarch64") {
-            Some(PathBuf::from("ntoaarch64-ar"))
-        } else if target.starts_with("x86_64") {
-            Some(PathBuf::from("ntox86_64-ar"))
-        } else {
-            panic!("Unknown architecture, cannot determine archiver for Neutrino QNX");
-        }
-    } else if target.contains("android") || target.contains("-wasi") {
-        Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar")))
-    } else {
-        Some(default_ar)
-    }
-}
-
 /// Creates and configures a new [`cc::Build`] instance for the given target.
 fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
     let mut cfg = cc::Build::new();
@@ -140,7 +110,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
     let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
         ar
     } else {
-        cc2ar(compiler.path(), target, PathBuf::from(cfg.get_archiver().get_program()))
+        cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()
     };
 
     build.cc.borrow_mut().insert(target, compiler.clone());
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index 43d61ce02c5..225fb7619b5 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -6,119 +6,6 @@ use crate::core::config::{Target, TargetSelection};
 use crate::{Build, Config, Flags};
 
 #[test]
-fn test_cc2ar_env_specific() {
-    let triple = "x86_64-unknown-linux-gnu";
-    let key = "AR_x86_64_unknown_linux_gnu";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::set_var(key, "custom-ar") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var(key) };
-    assert_eq!(result, Some(PathBuf::from("custom-ar")));
-}
-
-#[test]
-fn test_cc2ar_musl() {
-    let triple = "x86_64-unknown-linux-musl";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ar")));
-}
-
-#[test]
-fn test_cc2ar_openbsd() {
-    let triple = "x86_64-unknown-openbsd";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_openbsd") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/cc");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ar")));
-}
-
-#[test]
-fn test_cc2ar_vxworks() {
-    let triple = "armv7-wrs-vxworks";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_armv7_wrs_vxworks") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("wr-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_i586() {
-    let triple = "i586-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_i586_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntox86-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_aarch64() {
-    let triple = "aarch64-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_aarch64_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntoaarch64-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_x86_64() {
-    let triple = "x86_64-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntox86_64-ar")));
-}
-
-#[test]
-#[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")]
-fn test_cc2ar_nto_unknown() {
-    let triple = "powerpc-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_powerpc_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let _ = cc2ar(cc, target, default_ar);
-}
-
-#[test]
 fn test_ndk_compiler_c() {
     let ndk_path = PathBuf::from("/ndk");
     let target_triple = "arm-unknown-linux-android";
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 08e1c21e58e..561af34a447 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -46,7 +46,16 @@ pub fn dylib_path() -> Vec<std::path::PathBuf> {
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
 pub fn exe(name: &str, target: &str) -> String {
-    if target.contains("windows") {
+    // On Cygwin, the decision to append .exe or not is not as straightforward.
+    // Executable files do actually have .exe extensions so on hosts other than
+    // Cygwin it is necessary.  But on a Cygwin host there is magic happening
+    // that redirects requests for file X to file X.exe if it exists, and
+    // furthermore /proc/self/exe (and thus std::env::current_exe) always
+    // returns the name *without* the .exe extension.  For comparisons against
+    // that to match, we therefore do not append .exe for Cygwin targets on
+    // a Cygwin host.
+    if target.contains("windows") || (cfg!(not(target_os = "cygwin")) && target.contains("cygwin"))
+    {
         format!("{name}.exe")
     } else if target.contains("uefi") {
         format!("{name}.efi")
diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs
index 5600d7b4db5..60cbf50c7a3 100644
--- a/src/ci/citool/src/jobs.rs
+++ b/src/ci/citool/src/jobs.rs
@@ -85,14 +85,20 @@ impl JobDatabase {
 }
 
 pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
-    let mut db: Value = serde_yaml::from_str(db)?;
+    let mut db: Value = serde_yaml::from_str(db).context("failed to parse YAML content")?;
 
     // We need to expand merge keys (<<), because serde_yaml can't deal with them
     // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges.
-    db.apply_merge()?;
-    db.apply_merge()?;
 
-    let db: JobDatabase = serde_yaml::from_value(db)?;
+    let apply_merge = |db: &mut Value| -> anyhow::Result<()> {
+        db.apply_merge().context("failed to apply merge keys")
+    };
+
+    // Apply merge twice to handle nested merges
+    apply_merge(&mut db)?;
+    apply_merge(&mut db)?;
+
+    let db: JobDatabase = serde_yaml::from_value(db).context("failed to parse job database")?;
     Ok(db)
 }
 
diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile
index aade9588268..bc311be0580 100644
--- a/src/ci/docker/host-x86_64/arm-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile
@@ -28,6 +28,7 @@ RUN /scripts/android-sdk.sh
 ENV PATH=$PATH:/android/sdk/emulator
 ENV PATH=$PATH:/android/sdk/tools
 ENV PATH=$PATH:/android/sdk/platform-tools
+ENV PATH=$PATH:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
 
 ENV TARGETS=arm-linux-androideabi
 
diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile
index 95fed6ee767..7b73326e359 100644
--- a/src/ci/docker/host-x86_64/dist-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile
@@ -22,6 +22,8 @@ ENV RUST_CONFIGURE_ARGS \
       --android-ndk=/android/ndk/ \
       --disable-docs
 
+ENV PATH=$PATH:/android/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin
+
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile
new file mode 100644
index 00000000000..996dacd7124
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/Dockerfile
@@ -0,0 +1,35 @@
+FROM ghcr.io/rust-lang/ubuntu:22.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng.sh /scripts/
+RUN sh /scripts/crosstool-ng.sh
+
+WORKDIR /build
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+WORKDIR /tmp
+
+COPY scripts/crosstool-ng-build.sh /scripts/
+COPY host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig
+RUN /scripts/crosstool-ng-build.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
+
+ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
+    AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \
+    CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++
+
+ENV HOSTS=arm-unknown-linux-gnueabi
+
+ENV RUST_CONFIGURE_ARGS \
+      --enable-full-tools \
+      --disable-docs \
+      --enable-sanitizers \
+      --enable-profiler
+ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig
index e7afdbe9d4d..e7afdbe9d4d 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig
+++ b/src/ci/docker/host-x86_64/dist-arm-linux-gnueabi/arm-linux-gnueabi.defconfig
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile
index 3795859f308..6e055cd2bd5 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux-musl/Dockerfile
@@ -19,19 +19,13 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig
+COPY host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
-
-ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
-    AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \
-    CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++
-
-ENV HOSTS=arm-unknown-linux-gnueabi,aarch64-unknown-linux-musl
+ENV HOSTS=aarch64-unknown-linux-musl
 
 ENV RUST_CONFIGURE_ARGS \
       --enable-full-tools \
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig
new file mode 100644
index 00000000000..e7afdbe9d4d
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-arm-linux-musl/arm-linux-musl.defconfig
@@ -0,0 +1,13 @@
+CT_CONFIG_VERSION="4"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_USE_MIRROR=y
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_ARCH_ARM=y
+CT_ARCH_ARCH="armv6"
+CT_ARCH_FLOAT_SW=y
+CT_KERNEL_LINUX=y
+CT_LINUX_V_3_2=y
+CT_BINUTILS_V_2_32=y
+CT_GLIBC_V_2_17=y
+CT_GCC_V_8=y
+CT_CC_LANG_CXX=y
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile
new file mode 100644
index 00000000000..d2f1b9400ad
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/Dockerfile
@@ -0,0 +1,41 @@
+FROM ubuntu:22.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY scripts/crosstool-ng.sh /scripts/
+RUN sh /scripts/crosstool-ng.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+
+WORKDIR /tmp
+
+COPY scripts/crosstool-ng-build.sh /scripts/
+COPY host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig /tmp/crosstool.defconfig
+RUN /scripts/crosstool-ng-build.sh
+
+WORKDIR /build
+
+RUN apt-get install -y --no-install-recommends rpm2cpio cpio
+COPY scripts/shared.sh scripts/build-powerpc64le-toolchain.sh /build/
+RUN ./build-powerpc64le-toolchain.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV \
+    AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
+    CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
+    CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++
+
+ENV HOSTS=powerpc64le-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS \
+    --enable-extended \
+    --enable-full-tools \
+    --enable-profiler \
+    --enable-sanitizers \
+    --disable-docs
+
+ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig
new file mode 100644
index 00000000000..363e5850894
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-gnu/powerpc64le-unknown-linux-gnu.defconfig
@@ -0,0 +1,14 @@
+CT_CONFIG_VERSION="4"
+CT_EXPERIMENTAL=y
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_USE_MIRROR=y
+CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_ARCH_POWERPC=y
+CT_ARCH_LE=y
+CT_ARCH_64=y
+# CT_DEMULTILIB is not set
+CT_ARCH_ARCH="powerpc64le"
+CT_KERNEL_LINUX=y
+CT_LINUX_V_4_19=y
+CT_CC_LANG_CXX=y
+CT_GETTEXT_NEEDED=y
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile
index cb20f43cff7..f045b2a5f65 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/Dockerfile
@@ -12,13 +12,13 @@ RUN sh /scripts/rustbuild-setup.sh
 WORKDIR /tmp
 
 COPY scripts/crosstool-ng-build.sh /scripts/
-COPY host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig /tmp/crosstool.defconfig
+COPY host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig /tmp/crosstool.defconfig
 RUN /scripts/crosstool-ng-build.sh
 
 WORKDIR /build
 
 RUN apt-get install -y --no-install-recommends rpm2cpio cpio
-COPY scripts/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /build/
+COPY scripts/shared.sh scripts/build-powerpc64le-toolchain.sh /build/
 RUN ./build-powerpc64le-toolchain.sh
 
 COPY scripts/sccache.sh /scripts/
@@ -27,14 +27,11 @@ RUN sh /scripts/sccache.sh
 ENV PATH=$PATH:/x-tools/powerpc64le-unknown-linux-musl/bin
 
 ENV \
-    AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
-    CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
-    CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ \
     AR_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-ar \
     CC_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-gcc \
     CXX_powerpc64le_unknown_linux_musl=powerpc64le-unknown-linux-musl-g++
 
-ENV HOSTS=powerpc64le-unknown-linux-gnu,powerpc64le-unknown-linux-musl
+ENV HOSTS=powerpc64le-unknown-linux-musl
 
 ENV RUST_CONFIGURE_ARGS \
     --enable-extended \
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig
index c6cde30b2a4..c6cde30b2a4 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/powerpc64le-unknown-linux-musl.defconfig
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux-musl/powerpc64le-unknown-linux-musl.defconfig
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 36f7df2b069..4e69fb2f370 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -97,9 +97,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     docker --version
 
     REGISTRY=ghcr.io
-    # Hardcode username to reuse cache between auto and pr jobs
-    # FIXME: should be changed after move from rust-lang-ci
-    REGISTRY_USERNAME=rust-lang-ci
+    # Default to `rust-lang` to allow reusing the cache for local builds
+    REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER:-rust-lang}
     # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
     IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
     # Tag used to cache the Docker build
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/scripts/build-powerpc64le-toolchain.sh
index 56ea28b6ca5..56ea28b6ca5 100755
--- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
+++ b/src/ci/docker/scripts/build-powerpc64le-toolchain.sh
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index 1d280948ebe..fa18f67583f 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,8 @@
 
 set -euo pipefail
 
-LINUX_VERSION=v6.15-rc4
+# https://github.com/Rust-for-Linux/linux/issues/1163
+LINUX_VERSION=3ca02fc80cc4fdac63aaa6796642f1e07be591d6
 
 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt
 ../x.py build --stage 2 library rustdoc clippy rustfmt
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 42ad5acbdac..2daa8624605 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -10,11 +10,6 @@ runners:
     free_disk: true
     <<: *base-job
 
-  # Large runner used mainly for its bigger disk capacity
-  - &job-linux-4c-largedisk
-    os: ubuntu-24.04-4core-16gb
-    <<: *base-job
-
   - &job-linux-8c
     os: ubuntu-24.04-8core-32gb
     <<: *base-job
@@ -167,8 +162,11 @@ auto:
   - name: dist-android
     <<: *job-linux-4c
 
-  - name: dist-arm-linux
-    <<: *job-linux-8c-codebuild
+  - name: dist-arm-linux-gnueabi
+    <<: *job-linux-4c
+
+  - name: dist-arm-linux-musl
+    <<: *job-linux-4c
 
   - name: dist-armhf-linux
     <<: *job-linux-4c
@@ -203,8 +201,11 @@ auto:
   - name: dist-powerpc64-linux
     <<: *job-linux-4c
 
-  - name: dist-powerpc64le-linux
-    <<: *job-linux-4c-largedisk
+  - name: dist-powerpc64le-linux-gnu
+    <<: *job-linux-4c
+
+  - name: dist-powerpc64le-linux-musl
+    <<: *job-linux-4c
 
   - name: dist-riscv64-linux
     <<: *job-linux-4c
@@ -227,7 +228,7 @@ auto:
   - name: dist-x86_64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-linux-36c-codebuild
+    <<: *job-linux-16c
 
   - name: dist-x86_64-linux-alt
     env:
@@ -323,7 +324,7 @@ auto:
     <<: *job-linux-4c
 
   - name: x86_64-gnu-distcheck
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
   # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 5522095e304..a9528e92915 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -10,8 +10,8 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 # Update both macOS's and Windows's tarballs when bumping the version here.
-# Try to keep this in sync with src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
-LLVM_VERSION="18.1.4"
+# Try to keep this in sync with src/ci/docker/scripts/build-clang.sh
+LLVM_VERSION="20.1.3"
 
 if isMacOS; then
     # FIXME: This is the latest pre-built version of LLVM that's available for
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index c8c501e646a..ad852071f29 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -42,5 +42,5 @@ if isWindows && isKnownToBeMingwBuild; then
 
     curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
     7z x -y mingw.7z > /dev/null
-    ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
+    ciCommandAddPath "$(cygpath -m "$(pwd)/${mingw_dir}/bin")"
 fi
diff --git a/src/ci/scripts/install-ninja.sh b/src/ci/scripts/install-ninja.sh
index 23cbc2eb6d1..7ac19173923 100755
--- a/src/ci/scripts/install-ninja.sh
+++ b/src/ci/scripts/install-ninja.sh
@@ -12,7 +12,7 @@ if isWindows; then
     7z x -oninja ninja.zip
     rm ninja.zip
     ciCommandSetEnv "RUST_CONFIGURE_ARGS" "${RUST_CONFIGURE_ARGS} --enable-ninja"
-    ciCommandAddPath "$(pwd)/ninja"
+    ciCommandAddPath "$(cygpath -m "$(pwd)/ninja")"
 elif isMacOS; then
     brew install ninja
 fi
diff --git a/src/ci/scripts/install-sccache.sh b/src/ci/scripts/install-sccache.sh
index b055e76a805..fed06063fa0 100755
--- a/src/ci/scripts/install-sccache.sh
+++ b/src/ci/scripts/install-sccache.sh
@@ -15,7 +15,7 @@ elif isWindows; then
     mkdir -p sccache
     curl -fo sccache/sccache.exe \
       "${MIRRORS_BASE}/2025-02-24-sccache-v0.10.0-x86_64-pc-windows-msvc.exe"
-    ciCommandAddPath "$(pwd)/sccache"
+    ciCommandAddPath "$(cygpath -m "$(pwd)/sccache")"
 fi
 
 # FIXME: we should probably install sccache outside the containers and then
diff --git a/src/doc/book b/src/doc/book
-Subproject d33916341d480caede1d0ae57cbeae23aab23e8
+Subproject 230c68bc1e08f5f3228384a28cc228c81dfbd10
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 1b1bb49babd65c732468cfa515b0c009bd1d26b
+Subproject aa6ce337c0adf7a63e33960d184270f2a45ab9e
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 387392674d74656f7cb437c05a96f0c52ea8e60
+Subproject 118fd1f1f0854f50e3ae1fe4b64862aad23009c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 8a8918c698534547fa8a1a693cb3e7277f0bfb2
+Subproject c9d151f9147c4808c77f0375ba3fa5d54443cb9
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 5e4266f61da..0d889a5d5b9 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-414482f6a0d4e7290f614300581a0b55442552a3
+e42bbfe1f7c26f8760a99c4b1f27d33aba1040bb
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 31119496e75..a7b76233d19 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -134,9 +134,9 @@
 
 - [Command-line arguments](./cli.md)
 - [rustc_driver and rustc_interface](./rustc-driver/intro.md)
+    - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
     - [Example: Type checking](./rustc-driver/interacting-with-the-ast.md)
     - [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md)
-    - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
 - [Errors and lints](diagnostics.md)
     - [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md)
     - [Translation](./diagnostics/translation.md)
diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
index 513df1650c3..eeb2af5e6bc 100644
--- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
+++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
@@ -28,8 +28,8 @@ format is specific to `rustc`, and may change over time. This file contains:
   [`-C embed-bitcode=no`][embed-bitcode] CLI option to improve compile times
   and reduce disk space if LTO is not needed.
 * `rustc` [metadata], in a file named `lib.rmeta`.
-* A symbol table, which is generally a list of symbols with offsets to the
-  object file that contain that symbol. This is pretty standard for archive
+* A symbol table, which is essentially a list of symbols with offsets to the
+  object files that contain that symbol. This is pretty standard for archive
   files.
 
 [archive file]: https://en.wikipedia.org/wiki/Ar_(Unix)
@@ -46,12 +46,11 @@ A `dylib` is a platform-specific shared library. It includes the `rustc`
 
 ### rmeta
 
-An `rmeta` file is custom binary format that contains the [metadata] for the
-crate. This file can be used for fast "checks" of a project by skipping all
-code generation (as is done with `cargo check`), collecting enough information
-for documentation (as is done with `cargo doc`), or for
-[pipelining](#pipelining). This file is created if the
-[`--emit=metadata`][emit] CLI option is used.
+An `rmeta` file is a custom binary format that contains the [metadata] for the
+crate. This file can be used for fast "checks" of a project by skipping all code
+generation (as is done with `cargo check`), collecting enough information for
+documentation (as is done with `cargo doc`), or for [pipelining](#pipelining).
+This file is created if the [`--emit=metadata`][emit] CLI option is used.
 
 `rmeta` files do not support linking, since they do not contain compiled
 object files.
@@ -60,8 +59,8 @@ object files.
 
 ## Metadata
 
-The metadata contains a wide swath of different elements. This guide will not
-go into detail of every field it contains. You are encouraged to browse the
+The metadata contains a wide swath of different elements. This guide will not go
+into detail about every field it contains. You are encouraged to browse the
 [`CrateRoot`] definition to get a sense of the different elements it contains.
 Everything about metadata encoding and decoding is in the [`rustc_metadata`]
 package.
@@ -122,9 +121,9 @@ much more.
 
 By default, all Rust symbols are mangled and incorporate the stable crate id.
 This allows multiple versions of the same crate to be included together. Cargo
-automatically generates `-C metadata` hashes based on a variety of factors,
-like the package version, source, and the target kind (a lib and test can have
-the same crate name, so they need to be disambiguated).
+automatically generates `-C metadata` hashes based on a variety of factors, like
+the package version, source, and target kind (a lib and test can have the same
+crate name, so they need to be disambiguated).
 
 [`StableCrateId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html
 [`StableCrateId::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html#method.new
@@ -154,7 +153,7 @@ will also look at the [sysroot] to find dependencies.
 
 As crates are loaded, they are kept in the [`CStore`] with the crate metadata
 wrapped in the [`CrateMetadata`] struct. After resolution and expansion, the
-`CStore` will make its way into the [`GlobalCtxt`] for the rest of
+`CStore` will make its way into the [`GlobalCtxt`] for the rest of the
 compilation.
 
 [name resolution]: ../name-resolution.md
diff --git a/src/doc/rustc-dev-guide/src/cli.md b/src/doc/rustc-dev-guide/src/cli.md
index 408ae207004..4c77007ea44 100644
--- a/src/doc/rustc-dev-guide/src/cli.md
+++ b/src/doc/rustc-dev-guide/src/cli.md
@@ -28,6 +28,6 @@ adding a new command-line argument.
   unstable-options` flag.
 
 [cli-docs]: https://doc.rust-lang.org/rustc/command-line-arguments.html
-[forge guide for new options]: https://forge.rust-lang.org/compiler/new_option.html
+[forge guide for new options]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#compiler-flags
 [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/
 [`parse_bool`]: https://github.com/rust-lang/rust/blob/e5335592e78354e33d798d20c04bcd677c1df62d/src/librustc_session/options.rs#L307-L313
diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md
index 8bf14bef2a0..0e5b32a06f8 100644
--- a/src/doc/rustc-dev-guide/src/getting-started.md
+++ b/src/doc/rustc-dev-guide/src/getting-started.md
@@ -89,7 +89,7 @@ filtering the search to areas you're interested in. For example:
 Not all important or beginner work has issue labels.
 See below for how to find work that isn't labelled.
 
-[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+
+[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked:pr+
 [Triage]: ./contributing.md#issue-triage
 
 ### Recurring work
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
index 40500e6bc7a..a3684397b29 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
@@ -7,8 +7,8 @@ It acts as the glue for running the various phases of the compiler in the correc
 using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
 
 The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc].
-This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
-[`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
+This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`] and a couple of other optional options.
+[`Callbacks`] is a `trait` that allows for custom compiler configuration,
 as well as allowing custom code to run after different phases of the compilation.
 
 ## `rustc_interface`
@@ -33,14 +33,8 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc]
 [`Compiler`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Compiler.html
 [`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/
 [`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html
-[`Session`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html
-[`SourceMap`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html
-[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
-[Appendix A]: appendix/stupid-stats.html
-[cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
+[`Callbacks`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
 [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
 [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
 [rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html
 [rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
-[stupid-stats]: https://github.com/nrc/stupid-stats
-[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
diff --git a/src/doc/rustc/src/platform-support/solaris.md b/src/doc/rustc/src/platform-support/solaris.md
index 0452d76f6c2..c22b5c24c12 100644
--- a/src/doc/rustc/src/platform-support/solaris.md
+++ b/src/doc/rustc/src/platform-support/solaris.md
@@ -8,6 +8,7 @@ Rust for Solaris operating system.
 ## Target maintainers
 
 [@psumbera](https://github.com/psumbera)
+[@kulikjak](https://github.com/kulikjak)
 
 ## Requirements
 
diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css
index 58ca1f8b26f..fa709194f37 100644
--- a/src/doc/rustc/theme/pagetoc.css
+++ b/src/doc/rustc/theme/pagetoc.css
@@ -49,7 +49,7 @@
     }
     #pagetoc a {
         border-left: 1px solid var(--sidebar-bg);
-        color: var(--sidebar-fg) !important;
+        color: var(--fg);
         display: block;
         padding-bottom: 5px;
         padding-top: 5px;
diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
index 45146993371..6ec93d1746c 100644
--- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
+++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md
@@ -88,8 +88,10 @@ on your documentation examples make requests to.
 ```
 
 Now, when you press "run", the button will make a request to this domain. The request
-URL will contain 2 query parameters: `code` and `edition` for the code in the documentation
-and the Rust edition respectively.
+URL will contain 3 query parameters:
+1. `code` for the code in the documentation
+2. `version` for the Rust channel, e.g. nightly, which is decided by whether `code` contain unstable features
+3. `edition` for the Rust edition, e.g. 2024
 
 If you don't use this attribute, there will be no run buttons.
 
diff --git a/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md b/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md
new file mode 100644
index 00000000000..39f0c04a1b5
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/eagerly-emit-delayed-bugs.md
@@ -0,0 +1,12 @@
+# `eagerly-emit-delayed-bugs`
+
+This feature is perma-unstable and has no tracking issue.
+
+------------------------
+
+This flag converts all [`span_delayed_bug()`] calls to [`bug!`] calls, exiting the compiler immediately and allowing you to generate a backtrace of where the delayed bug occurred.
+For full documentation, see [the rustc-dev-guide][dev-guide-delayed].
+
+[`bug!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/macro.bug.html
+[`span_delayed_bug()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxtHandle.html#method.span_delayed_bug
+[dev-guide-delayed]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#debugging-delayed-bugs
diff --git a/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md b/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md
new file mode 100644
index 00000000000..48620214407
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/track-diagnostics.md
@@ -0,0 +1,11 @@
+# `track-diagnostics`
+
+This feature is perma-unstable and has no tracking issue.
+
+------------------------
+
+This flag prints the source code span in the compiler where a diagnostic was generated, respecting [`#[track_caller]`][track_caller]. Note that this may be different from the place it was emitted.
+For full documentation, see [the rustc-dev-guide][dev-guide-track-diagnostics].
+
+[track_caller]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute
+[dev-guide-track-diagnostics]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#getting-the-error-creation-location
diff --git a/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md b/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md
new file mode 100644
index 00000000000..df7c380a50b
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/treat-err-as-bug.md
@@ -0,0 +1,13 @@
+# `treat-err-as-bug`
+
+This feature is perma-unstable and has no tracking issue.
+
+------------------------
+
+This flag converts the selected error to a [`bug!`] call, exiting the compiler immediately and allowing you to generate a backtrace of where the error occurred.
+For full documentation, see [the rustc-dev-guide][dev-guide-backtrace].
+
+Note that the compiler automatically sets `RUST_BACKTRACE=1` for itself, and so you do not need to set it yourself when using this flag.
+
+[`bug!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/macro.bug.html
+[dev-guide-backtrace]: https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#getting-a-backtrace-for-errors
diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
index ba622466ba7..7728f6725b1 100644
--- a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
+++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
@@ -1,6 +1,6 @@
 # `explicit_extern_abis`
 
-The tracking issue for this feature is: #134986
+The tracking issue for this feature is: [#134986]
 
 ------
 
@@ -21,3 +21,5 @@ extern "C" fn function2() {} // compiles
 
 extern "aapcs" fn function3() {} // compiles
 ```
+
+[#134986]: https://github.com/rust-lang/rust/issues/134986
diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el
index 90bd38aa894..3cb229cd98c 100644
--- a/src/etc/rust_analyzer_eglot.el
+++ b/src/etc/rust_analyzer_eglot.el
@@ -14,7 +14,7 @@
                                   "src/bootstrap/Cargo.toml"
                                   "src/tools/rust-analyzer/Cargo.toml"]
                  :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
-                                              "--edition=2021"])
+                                              "--edition=2024"])
                  :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
                                       :enable t)
                  :cargo ( :buildScripts ( :enable t
diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml
index 05fc7716a72..1a6a14991ec 100644
--- a/src/etc/rust_analyzer_helix.toml
+++ b/src/etc/rust_analyzer_helix.toml
@@ -32,7 +32,7 @@ overrideCommand = [
 [language-server.rust-analyzer.config.rustfmt]
 overrideCommand = [
     "build/rust-analyzer/host/rustfmt/bin/rustfmt",
-    "--edition=2021"
+    "--edition=2024"
 ]
 
 [language-server.rust-analyzer.config.procMacro]
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index 5ce886a9b65..a960cc01732 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -17,7 +17,7 @@
     ],
     "rust-analyzer.rustfmt.overrideCommand": [
         "${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
-        "--edition=2021"
+        "--edition=2024"
     ],
     "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
     "rust-analyzer.procMacro.enable": true,
diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json
index 3461ff887d9..27fc524e9b5 100644
--- a/src/etc/rust_analyzer_zed.json
+++ b/src/etc/rust_analyzer_zed.json
@@ -29,15 +29,15 @@
         ],
         "procMacro": {
           "enable": true,
-          "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+          "server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
         },
         "rustc": {
           "source": "./Cargo.toml"
         },
         "rustfmt": {
           "overrideCommand": [
-            "${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
-            "--edition=2021"
+            "build/host/rustfmt/bin/rustfmt",
+            "--edition=2024"
           ]
         },
         "server": {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 75f1bc9549c..07ecd98f775 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,7 +5,9 @@ use std::{fmt, iter};
 
 use arrayvec::ArrayVec;
 use rustc_abi::{ExternAbi, VariantIdx};
-use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
+use rustc_attr_data_structures::{
+    AttributeKind, ConstStability, Deprecation, Stability, StableSince,
+};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -403,13 +405,13 @@ impl Item {
             // versions; the paths that are exposed through it are "deprecated" because they
             // were never supposed to work at all.
             let stab = self.stability(tcx)?;
-            if let rustc_attr_parsing::StabilityLevel::Stable {
+            if let rustc_attr_data_structures::StabilityLevel::Stable {
                 allowed_through_unstable_modules: Some(note),
                 ..
             } = stab.level
             {
                 Some(Deprecation {
-                    since: rustc_attr_parsing::DeprecatedSince::Unspecified,
+                    since: rustc_attr_data_structures::DeprecatedSince::Unspecified,
                     note: Some(note),
                     suggestion: None,
                 })
@@ -772,20 +774,11 @@ impl Item {
             .filter_map(|attr| {
                 if is_json {
                     match attr {
-                        hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
-                            // rustdoc-json stores this in `Item::deprecation`, so we
-                            // don't want it it `Item::attrs`.
-                            None
-                        }
-                        rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
-                            ..,
-                        )) => {
-                            // We have separate pretty-printing logic for `#[repr(..)]` attributes.
-                            // For example, there are circumstances where `#[repr(transparent)]`
-                            // is applied but should not be publicly shown in rustdoc
-                            // because it isn't public API.
-                            None
-                        }
+                        // rustdoc-json stores this in `Item::deprecation`, so we
+                        // don't want it it `Item::attrs`.
+                        hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
+                        // We have separate pretty-printing logic for `#[repr(..)]` attributes.
+                        hir::Attribute::Parsed(AttributeKind::Repr(..)) => None,
                         _ => Some({
                             let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
                             assert_eq!(s.pop(), Some('\n'));
@@ -818,7 +811,8 @@ impl Item {
             if repr.transparent() {
                 // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
                 // field is public in case all fields are 1-ZST fields.
-                let render_transparent = cache.document_private
+                let render_transparent = is_json
+                    || cache.document_private
                     || adt
                         .all_fields()
                         .find(|field| {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index af7986d030e..2e38b6cdc65 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,7 +1,7 @@
 use std::assert_matches::debug_assert_matches;
 use std::fmt::{self, Display, Write as _};
-use std::mem;
 use std::sync::LazyLock as Lazy;
+use std::{ascii, mem};
 
 use rustc_ast::tokenstream::TokenTree;
 use rustc_hir::def::{DefKind, Res};
@@ -24,7 +24,7 @@ use crate::clean::{
     clean_middle_ty, inline,
 };
 use crate::core::DocContext;
-use crate::display::Joined as _;
+use crate::display::{Joined as _, MaybeDisplay as _};
 
 #[cfg(test)]
 mod tests;
@@ -254,14 +254,7 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     fmt::from_fn(|f| {
         segments
             .iter()
-            .map(|seg| {
-                fmt::from_fn(|f| {
-                    if seg.ident.name != kw::PathRoot {
-                        write!(f, "{}", seg.ident)?;
-                    }
-                    Ok(())
-                })
-            })
+            .map(|seg| (seg.ident.name != kw::PathRoot).then_some(seg.ident).maybe_display())
             .joined("::", f)
     })
     .to_string()
@@ -391,30 +384,12 @@ pub(crate) fn print_evaluated_const(
     })
 }
 
-fn format_integer_with_underscore_sep(num: &str) -> String {
-    let num_chars: Vec<_> = num.chars().collect();
-    let mut num_start_index = if num_chars.first() == Some(&'-') { 1 } else { 0 };
-    let chunk_size = match &num.as_bytes()[num_start_index..] {
-        [b'0', b'b' | b'x', ..] => {
-            num_start_index += 2;
-            4
-        }
-        [b'0', b'o', ..] => {
-            num_start_index += 2;
-            let remaining_chars = num_chars.len() - num_start_index;
-            if remaining_chars <= 6 {
-                // don't add underscores to Unix permissions like 0755 or 100755
-                return num.to_string();
-            }
-            3
-        }
-        _ => 3,
-    };
-
-    num_chars[..num_start_index]
-        .iter()
-        .chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten())
-        .collect()
+fn format_integer_with_underscore_sep(num: u128, is_negative: bool) -> String {
+    let num = num.to_string();
+    let chars = num.as_ascii().unwrap();
+    let mut result = if is_negative { "-".to_string() } else { String::new() };
+    result.extend(chars.rchunks(3).rev().intersperse(&[ascii::Char::LowLine]).flatten());
+    result
 }
 
 fn print_const_with_custom_print_scalar<'tcx>(
@@ -428,7 +403,10 @@ fn print_const_with_custom_print_scalar<'tcx>(
     match (ct, ct.ty().kind()) {
         (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
             let mut output = if with_underscores {
-                format_integer_with_underscore_sep(&int.to_string())
+                format_integer_with_underscore_sep(
+                    int.assert_scalar_int().to_bits_unchecked(),
+                    false,
+                )
             } else {
                 int.to_string()
             };
@@ -445,7 +423,10 @@ fn print_const_with_custom_print_scalar<'tcx>(
                 .size;
             let sign_extended_data = int.assert_scalar_int().to_int(size);
             let mut output = if with_underscores {
-                format_integer_with_underscore_sep(&sign_extended_data.to_string())
+                format_integer_with_underscore_sep(
+                    sign_extended_data.unsigned_abs(),
+                    sign_extended_data.is_negative(),
+                )
             } else {
                 sign_extended_data.to_string()
             };
diff --git a/src/librustdoc/clean/utils/tests.rs b/src/librustdoc/clean/utils/tests.rs
index ebf4b495483..65c8255b2f2 100644
--- a/src/librustdoc/clean/utils/tests.rs
+++ b/src/librustdoc/clean/utils/tests.rs
@@ -2,40 +2,10 @@ use super::*;
 
 #[test]
 fn int_format_decimal() {
-    assert_eq!(format_integer_with_underscore_sep("12345678"), "12_345_678");
-    assert_eq!(format_integer_with_underscore_sep("123"), "123");
-    assert_eq!(format_integer_with_underscore_sep("123459"), "123_459");
-    assert_eq!(format_integer_with_underscore_sep("-12345678"), "-12_345_678");
-    assert_eq!(format_integer_with_underscore_sep("-123"), "-123");
-    assert_eq!(format_integer_with_underscore_sep("-123459"), "-123_459");
-}
-
-#[test]
-fn int_format_hex() {
-    assert_eq!(format_integer_with_underscore_sep("0xab3"), "0xab3");
-    assert_eq!(format_integer_with_underscore_sep("0xa2345b"), "0xa2_345b");
-    assert_eq!(format_integer_with_underscore_sep("0xa2e6345b"), "0xa2e6_345b");
-    assert_eq!(format_integer_with_underscore_sep("-0xab3"), "-0xab3");
-    assert_eq!(format_integer_with_underscore_sep("-0xa2345b"), "-0xa2_345b");
-    assert_eq!(format_integer_with_underscore_sep("-0xa2e6345b"), "-0xa2e6_345b");
-}
-
-#[test]
-fn int_format_binary() {
-    assert_eq!(format_integer_with_underscore_sep("0o12345671"), "0o12_345_671");
-    assert_eq!(format_integer_with_underscore_sep("0o123"), "0o123");
-    assert_eq!(format_integer_with_underscore_sep("0o123451"), "0o123451");
-    assert_eq!(format_integer_with_underscore_sep("-0o12345671"), "-0o12_345_671");
-    assert_eq!(format_integer_with_underscore_sep("-0o123"), "-0o123");
-    assert_eq!(format_integer_with_underscore_sep("-0o123451"), "-0o123451");
-}
-
-#[test]
-fn int_format_octal() {
-    assert_eq!(format_integer_with_underscore_sep("0b101"), "0b101");
-    assert_eq!(format_integer_with_underscore_sep("0b101101011"), "0b1_0110_1011");
-    assert_eq!(format_integer_with_underscore_sep("0b01101011"), "0b0110_1011");
-    assert_eq!(format_integer_with_underscore_sep("-0b101"), "-0b101");
-    assert_eq!(format_integer_with_underscore_sep("-0b101101011"), "-0b1_0110_1011");
-    assert_eq!(format_integer_with_underscore_sep("-0b01101011"), "-0b0110_1011");
+    assert_eq!(format_integer_with_underscore_sep(12345678, false), "12_345_678");
+    assert_eq!(format_integer_with_underscore_sep(123, false), "123");
+    assert_eq!(format_integer_with_underscore_sep(123459, false), "123_459");
+    assert_eq!(format_integer_with_underscore_sep(12345678, true), "-12_345_678");
+    assert_eq!(format_integer_with_underscore_sep(123, true), "-123");
+    assert_eq!(format_integer_with_underscore_sep(123459, true), "-123_459");
 }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index ef70b862185..b2fe24db0a2 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -12,7 +12,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex};
 use std::{panic, str};
 
-pub(crate) use make::DocTestBuilder;
+pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder};
 pub(crate) use markdown::test as test_markdown;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_errors::emitter::HumanReadableErrorType;
@@ -23,9 +23,9 @@ use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::interface;
 use rustc_session::config::{self, CrateType, ErrorOutputType, Input};
 use rustc_session::lint;
-use rustc_span::FileName;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
+use rustc_span::{FileName, Span};
 use rustc_target::spec::{Target, TargetTuple};
 use tempfile::{Builder as TempFileBuilder, TempDir};
 use tracing::debug;
@@ -197,7 +197,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
                 }
             } else {
                 let mut collector = CreateRunnableDocTests::new(options, opts);
-                tests.into_iter().for_each(|t| collector.add_test(t));
+                tests.into_iter().for_each(|t| collector.add_test(t, Some(compiler.sess.dcx())));
 
                 Ok(Some(collector))
             }
@@ -847,6 +847,7 @@ pub(crate) struct ScrapedDocTest {
     langstr: LangString,
     text: String,
     name: String,
+    span: Span,
 }
 
 impl ScrapedDocTest {
@@ -856,6 +857,7 @@ impl ScrapedDocTest {
         logical_path: Vec<String>,
         langstr: LangString,
         text: String,
+        span: Span,
     ) -> Self {
         let mut item_path = logical_path.join("::");
         item_path.retain(|c| c != ' ');
@@ -865,7 +867,7 @@ impl ScrapedDocTest {
         let name =
             format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly());
 
-        Self { filename, line, langstr, text, name }
+        Self { filename, line, langstr, text, name, span }
     }
     fn edition(&self, opts: &RustdocOptions) -> Edition {
         self.langstr.edition.unwrap_or(opts.edition)
@@ -921,7 +923,7 @@ impl CreateRunnableDocTests {
         }
     }
 
-    fn add_test(&mut self, scraped_test: ScrapedDocTest) {
+    fn add_test(&mut self, scraped_test: ScrapedDocTest, dcx: Option<DiagCtxtHandle<'_>>) {
         // For example `module/file.rs` would become `module_file_rs`
         let file = scraped_test
             .filename
@@ -945,14 +947,14 @@ impl CreateRunnableDocTests {
         );
 
         let edition = scraped_test.edition(&self.rustdoc_options);
-        let doctest = DocTestBuilder::new(
-            &scraped_test.text,
-            Some(&self.opts.crate_name),
-            edition,
-            self.can_merge_doctests,
-            Some(test_id),
-            Some(&scraped_test.langstr),
-        );
+        let doctest = BuildDocTestBuilder::new(&scraped_test.text)
+            .crate_name(&self.opts.crate_name)
+            .edition(edition)
+            .can_merge_doctests(self.can_merge_doctests)
+            .test_id(test_id)
+            .lang_str(&scraped_test.langstr)
+            .span(scraped_test.span)
+            .build(dcx);
         let is_standalone = !doctest.can_be_merged
             || scraped_test.langstr.compile_fail
             || scraped_test.langstr.test_harness
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs
index ce362eabfc4..3b17ccc78c7 100644
--- a/src/librustdoc/doctest/extracted.rs
+++ b/src/librustdoc/doctest/extracted.rs
@@ -5,7 +5,7 @@
 
 use serde::Serialize;
 
-use super::{DocTestBuilder, ScrapedDocTest};
+use super::{BuildDocTestBuilder, ScrapedDocTest};
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown;
 
@@ -35,16 +35,13 @@ impl ExtractedDocTests {
     ) {
         let edition = scraped_test.edition(options);
 
-        let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test;
+        let ScrapedDocTest { filename, line, langstr, text, name, .. } = scraped_test;
 
-        let doctest = DocTestBuilder::new(
-            &text,
-            Some(&opts.crate_name),
-            edition,
-            false,
-            None,
-            Some(&langstr),
-        );
+        let doctest = BuildDocTestBuilder::new(&text)
+            .crate_name(&opts.crate_name)
+            .edition(edition)
+            .lang_str(&langstr)
+            .build(None);
         let (full_test_code, size) = doctest.generate_unique_doctest(
             &text,
             langstr.test_harness,
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index d4fbfb12582..66647b88018 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -8,14 +8,14 @@ use std::sync::Arc;
 use rustc_ast::token::{Delimiter, TokenKind};
 use rustc_ast::tokenstream::TokenTree;
 use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind};
-use rustc_errors::ColorConfig;
 use rustc_errors::emitter::stderr_destination;
+use rustc_errors::{ColorConfig, DiagCtxtHandle};
 use rustc_parse::new_parser_from_source_str;
 use rustc_session::parse::ParseSess;
-use rustc_span::edition::Edition;
+use rustc_span::edition::{DEFAULT_EDITION, Edition};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
-use rustc_span::{FileName, kw};
+use rustc_span::{DUMMY_SP, FileName, Span, kw};
 use tracing::debug;
 
 use super::GlobalTestOptions;
@@ -35,33 +35,78 @@ struct ParseSourceInfo {
     maybe_crate_attrs: String,
 }
 
-/// This struct contains information about the doctest itself which is then used to generate
-/// doctest source code appropriately.
-pub(crate) struct DocTestBuilder {
-    pub(crate) supports_color: bool,
-    pub(crate) already_has_extern_crate: bool,
-    pub(crate) has_main_fn: bool,
-    pub(crate) crate_attrs: String,
-    /// If this is a merged doctest, it will be put into `everything_else`, otherwise it will
-    /// put into `crate_attrs`.
-    pub(crate) maybe_crate_attrs: String,
-    pub(crate) crates: String,
-    pub(crate) everything_else: String,
-    pub(crate) test_id: Option<String>,
-    pub(crate) invalid_ast: bool,
-    pub(crate) can_be_merged: bool,
+/// Builder type for `DocTestBuilder`.
+pub(crate) struct BuildDocTestBuilder<'a> {
+    source: &'a str,
+    crate_name: Option<&'a str>,
+    edition: Edition,
+    can_merge_doctests: bool,
+    // If `test_id` is `None`, it means we're generating code for a code example "run" link.
+    test_id: Option<String>,
+    lang_str: Option<&'a LangString>,
+    span: Span,
 }
 
-impl DocTestBuilder {
-    pub(crate) fn new(
-        source: &str,
-        crate_name: Option<&str>,
-        edition: Edition,
-        can_merge_doctests: bool,
-        // If `test_id` is `None`, it means we're generating code for a code example "run" link.
-        test_id: Option<String>,
-        lang_str: Option<&LangString>,
-    ) -> Self {
+impl<'a> BuildDocTestBuilder<'a> {
+    pub(crate) fn new(source: &'a str) -> Self {
+        Self {
+            source,
+            crate_name: None,
+            edition: DEFAULT_EDITION,
+            can_merge_doctests: false,
+            test_id: None,
+            lang_str: None,
+            span: DUMMY_SP,
+        }
+    }
+
+    #[inline]
+    pub(crate) fn crate_name(mut self, crate_name: &'a str) -> Self {
+        self.crate_name = Some(crate_name);
+        self
+    }
+
+    #[inline]
+    pub(crate) fn can_merge_doctests(mut self, can_merge_doctests: bool) -> Self {
+        self.can_merge_doctests = can_merge_doctests;
+        self
+    }
+
+    #[inline]
+    pub(crate) fn test_id(mut self, test_id: String) -> Self {
+        self.test_id = Some(test_id);
+        self
+    }
+
+    #[inline]
+    pub(crate) fn lang_str(mut self, lang_str: &'a LangString) -> Self {
+        self.lang_str = Some(lang_str);
+        self
+    }
+
+    #[inline]
+    pub(crate) fn span(mut self, span: Span) -> Self {
+        self.span = span;
+        self
+    }
+
+    #[inline]
+    pub(crate) fn edition(mut self, edition: Edition) -> Self {
+        self.edition = edition;
+        self
+    }
+
+    pub(crate) fn build(self, dcx: Option<DiagCtxtHandle<'_>>) -> DocTestBuilder {
+        let BuildDocTestBuilder {
+            source,
+            crate_name,
+            edition,
+            can_merge_doctests,
+            // If `test_id` is `None`, it means we're generating code for a code example "run" link.
+            test_id,
+            lang_str,
+            span,
+        } = self;
         let can_merge_doctests = can_merge_doctests
             && lang_str.is_some_and(|lang_str| {
                 !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate
@@ -69,7 +114,7 @@ impl DocTestBuilder {
 
         let result = rustc_driver::catch_fatal_errors(|| {
             rustc_span::create_session_if_not_set_then(edition, |_| {
-                parse_source(source, &crate_name)
+                parse_source(source, &crate_name, dcx, span)
             })
         });
 
@@ -87,7 +132,7 @@ impl DocTestBuilder {
         else {
             // If the AST returned an error, we don't want this doctest to be merged with the
             // others.
-            return Self::invalid(
+            return DocTestBuilder::invalid(
                 String::new(),
                 String::new(),
                 String::new(),
@@ -107,7 +152,7 @@ impl DocTestBuilder {
             // If this is a merged doctest and a defined macro uses `$crate`, then the path will
             // not work, so better not put it into merged doctests.
             && !(has_macro_def && everything_else.contains("$crate"));
-        Self {
+        DocTestBuilder {
             supports_color,
             has_main_fn,
             crate_attrs,
@@ -120,7 +165,26 @@ impl DocTestBuilder {
             can_be_merged,
         }
     }
+}
 
+/// This struct contains information about the doctest itself which is then used to generate
+/// doctest source code appropriately.
+pub(crate) struct DocTestBuilder {
+    pub(crate) supports_color: bool,
+    pub(crate) already_has_extern_crate: bool,
+    pub(crate) has_main_fn: bool,
+    pub(crate) crate_attrs: String,
+    /// If this is a merged doctest, it will be put into `everything_else`, otherwise it will
+    /// put into `crate_attrs`.
+    pub(crate) maybe_crate_attrs: String,
+    pub(crate) crates: String,
+    pub(crate) everything_else: String,
+    pub(crate) test_id: Option<String>,
+    pub(crate) invalid_ast: bool,
+    pub(crate) can_be_merged: bool,
+}
+
+impl DocTestBuilder {
     fn invalid(
         crate_attrs: String,
         maybe_crate_attrs: String,
@@ -289,7 +353,12 @@ fn reset_error_count(psess: &ParseSess) {
 
 const DOCTEST_CODE_WRAPPER: &str = "fn f(){";
 
-fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceInfo, ()> {
+fn parse_source(
+    source: &str,
+    crate_name: &Option<&str>,
+    parent_dcx: Option<DiagCtxtHandle<'_>>,
+    span: Span,
+) -> Result<ParseSourceInfo, ()> {
     use rustc_errors::DiagCtxt;
     use rustc_errors::emitter::{Emitter, HumanEmitter};
     use rustc_span::source_map::FilePathMapping;
@@ -466,8 +535,17 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
                 }
             }
             if has_non_items {
-                // FIXME: if `info.has_main_fn` is `true`, emit a warning here to mention that
-                // this code will not be called.
+                if info.has_main_fn
+                    && let Some(dcx) = parent_dcx
+                    && !span.is_dummy()
+                {
+                    dcx.span_warn(
+                        span,
+                        "the `main` function of this doctest won't be run as it contains \
+                         expressions at the top level, meaning that the whole doctest code will be \
+                         wrapped in a function",
+                    );
+                }
                 info.has_main_fn = false;
             }
             Ok(info)
diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs
index b3a3ce08a05..e358a7e44e5 100644
--- a/src/librustdoc/doctest/markdown.rs
+++ b/src/librustdoc/doctest/markdown.rs
@@ -4,7 +4,7 @@ use std::fs::read_to_string;
 use std::sync::{Arc, Mutex};
 
 use rustc_session::config::Input;
-use rustc_span::FileName;
+use rustc_span::{DUMMY_SP, FileName};
 use tempfile::tempdir;
 
 use super::{
@@ -24,7 +24,14 @@ impl DocTestVisitor for MdCollector {
         let filename = self.filename.clone();
         // First line of Markdown is line 1.
         let line = 1 + rel_line.offset();
-        self.tests.push(ScrapedDocTest::new(filename, line, self.cur_path.clone(), config, test));
+        self.tests.push(ScrapedDocTest::new(
+            filename,
+            line,
+            self.cur_path.clone(),
+            config,
+            test,
+            DUMMY_SP,
+        ));
     }
 
     fn visit_header(&mut self, name: &str, level: u32) {
@@ -107,7 +114,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> {
     find_testable_code(&input_str, &mut md_collector, codes, None);
 
     let mut collector = CreateRunnableDocTests::new(options.clone(), opts);
-    md_collector.tests.into_iter().for_each(|t| collector.add_test(t));
+    md_collector.tests.into_iter().for_each(|t| collector.add_test(t, None));
     let CreateRunnableDocTests { opts, rustdoc_options, standalone_tests, mergeable_tests, .. } =
         collector;
     crate::doctest::run_tests(
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index 43dcfab880b..f9d2aa3d3b4 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -1,5 +1,6 @@
 //! Doctest functionality used only for doctests in `.rs` source files.
 
+use std::cell::Cell;
 use std::env;
 use std::sync::Arc;
 
@@ -47,13 +48,33 @@ impl RustCollector {
 
 impl DocTestVisitor for RustCollector {
     fn visit_test(&mut self, test: String, config: LangString, rel_line: MdRelLine) {
-        let line = self.get_base_line() + rel_line.offset();
+        let base_line = self.get_base_line();
+        let line = base_line + rel_line.offset();
+        let count = Cell::new(base_line);
+        let span = if line > base_line {
+            match self.source_map.span_extend_while(self.position, |c| {
+                if c == '\n' {
+                    let count_v = count.get();
+                    count.set(count_v + 1);
+                    if count_v >= line {
+                        return false;
+                    }
+                }
+                true
+            }) {
+                Ok(sp) => self.source_map.span_extend_to_line(sp.shrink_to_hi()),
+                _ => self.position,
+            }
+        } else {
+            self.position
+        };
         self.tests.push(ScrapedDocTest::new(
             self.get_filename(),
             line,
             self.cur_path.clone(),
             config,
             test,
+            span,
         ));
     }
 
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index 618c2041b43..08248fdf39b 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -1,8 +1,6 @@
 use std::path::PathBuf;
 
-use rustc_span::edition::DEFAULT_EDITION;
-
-use super::{DocTestBuilder, GlobalTestOptions};
+use super::{BuildDocTestBuilder, GlobalTestOptions};
 
 fn make_test(
     test_code: &str,
@@ -11,14 +9,14 @@ fn make_test(
     opts: &GlobalTestOptions,
     test_id: Option<&str>,
 ) -> (String, usize) {
-    let doctest = DocTestBuilder::new(
-        test_code,
-        crate_name,
-        DEFAULT_EDITION,
-        false,
-        test_id.map(|s| s.to_string()),
-        None,
-    );
+    let mut builder = BuildDocTestBuilder::new(test_code);
+    if let Some(crate_name) = crate_name {
+        builder = builder.crate_name(crate_name);
+    }
+    if let Some(test_id) = test_id {
+        builder = builder.test_id(test_id.to_string());
+    }
+    let doctest = builder.build(None);
     let (code, line_offset) =
         doctest.generate_unique_doctest(test_code, dont_insert_main, opts, crate_name);
     (code, line_offset)
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 19402004ed5..4989bd718c9 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -1,6 +1,6 @@
 use std::mem;
 
-use rustc_attr_parsing::StabilityLevel;
+use rustc_attr_data_structures::StabilityLevel;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
 use rustc_middle::ty::{self, TyCtxt};
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8c7ab640bed..486d4ae932d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -15,7 +15,7 @@ use std::slice;
 
 use itertools::Either;
 use rustc_abi::ExternAbi;
-use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince};
+use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 44b3be23914..3b5f9b5a458 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,4 +1,4 @@
-use std::fmt::{self, Display};
+use std::fmt::Display;
 use std::path::PathBuf;
 
 use askama::Template;
@@ -71,23 +71,6 @@ struct PageLayout<'a> {
 
 pub(crate) use crate::html::render::sidebar::filters;
 
-/// Implements [`Display`] for a function that accepts a mutable reference to a [`String`], and (optionally) writes to it.
-///
-/// The wrapped function will receive an empty string, and can modify it,
-/// and the `Display` implementation will write the contents of the string after the function has finished.
-pub(crate) struct BufDisplay<F>(pub F);
-
-impl<F> Display for BufDisplay<F>
-where
-    F: Fn(&mut String),
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut buf = String::new();
-        self.0(&mut buf);
-        f.write_str(&buf)
-    }
-}
-
 pub(crate) fn render<T: Display, S: Display>(
     layout: &Layout,
     page: &Page<'_>,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index fc46293e7ea..ad7dfafd90c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -303,7 +303,11 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                 attrs: vec![],
                 args_file: PathBuf::new(),
             };
-            let doctest = doctest::DocTestBuilder::new(&test, krate, edition, false, None, None);
+            let mut builder = doctest::BuildDocTestBuilder::new(&test).edition(edition);
+            if let Some(krate) = krate {
+                builder = builder.crate_name(krate);
+            }
+            let doctest = builder.build(None);
             let (test, _) = doctest.generate_unique_doctest(&test, false, &opts, krate);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index f22935df96c..1f7201b8ca8 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -28,11 +28,10 @@ use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::format::join_with_double_colon;
-use crate::html::layout::{self, BufDisplay};
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
-use crate::html::{sources, static_files};
+use crate::html::{layout, sources, static_files};
 use crate::scrape_examples::AllCallLocations;
 use crate::{DOC_RUST_LANG_ORG_VERSION, try_err};
 
@@ -250,9 +249,7 @@ impl<'tcx> Context<'tcx> {
             layout::render(
                 &self.shared.layout,
                 &page,
-                BufDisplay(|buf: &mut String| {
-                    print_sidebar(self, it, buf);
-                }),
+                fmt::from_fn(|f| print_sidebar(self, it, f)),
                 content,
                 &self.shared.style_files,
             )
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index beaa6497b8c..06cb9269cc8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -49,7 +49,7 @@ use std::{fs, str};
 
 use askama::Template;
 use itertools::Either;
-use rustc_attr_parsing::{
+use rustc_attr_data_structures::{
     ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
@@ -538,7 +538,7 @@ fn document(
     }
 
     fmt::from_fn(move |f| {
-        document_item_info(cx, item, parent).render_into(f).unwrap();
+        document_item_info(cx, item, parent).render_into(f)?;
         if parent.is_none() {
             write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
         } else {
@@ -582,7 +582,7 @@ fn document_short(
     show_def_docs: bool,
 ) -> impl fmt::Display {
     fmt::from_fn(move |f| {
-        document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
+        document_item_info(cx, item, Some(parent)).render_into(f)?;
         if !show_def_docs {
             return Ok(());
         }
@@ -661,7 +661,7 @@ fn document_full_inner(
         };
 
         if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
-            render_call_locations(f, cx, item);
+            render_call_locations(f, cx, item)?;
         }
         Ok(())
     })
@@ -2584,11 +2584,15 @@ const MAX_FULL_EXAMPLES: usize = 5;
 const NUM_VISIBLE_LINES: usize = 10;
 
 /// Generates the HTML for example call locations generated via the --scrape-examples flag.
-fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean::Item) {
+fn render_call_locations<W: fmt::Write>(
+    mut w: W,
+    cx: &Context<'_>,
+    item: &clean::Item,
+) -> fmt::Result {
     let tcx = cx.tcx();
     let def_id = item.item_id.expect_def_id();
     let key = tcx.def_path_hash(def_id);
-    let Some(call_locations) = cx.shared.call_locations.get(&key) else { return };
+    let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) };
 
     // Generate a unique ID so users can link to this section for a given method
     let id = cx.derive_id("scraped-examples");
@@ -2602,8 +2606,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
           </h5>",
         root_path = cx.root_path(),
         id = id
-    )
-    .unwrap();
+    )?;
 
     // Create a URL to a particular location in a reverse-dependency's source file
     let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
@@ -2705,7 +2708,8 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
                 title: init_title,
                 locations: locations_encoded,
             }),
-        );
+        )
+        .unwrap();
 
         true
     };
@@ -2761,8 +2765,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
                   <div class=\"hide-more\">Hide additional examples</div>\
                   <div class=\"more-scraped-examples\">\
                     <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
-        )
-        .unwrap();
+        )?;
 
         // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
         // make the page arbitrarily huge!
@@ -2774,9 +2777,8 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
         if it.peek().is_some() {
             w.write_str(
                 r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
-            )
-            .unwrap();
-            it.for_each(|(_, call_data)| {
+            )?;
+            it.try_for_each(|(_, call_data)| {
                 let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
                 write!(
                     w,
@@ -2784,13 +2786,12 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
                     url = url,
                     name = call_data.display_name
                 )
-                .unwrap();
-            });
-            w.write_str("</ul></div>").unwrap();
+            })?;
+            w.write_str("</ul></div>")?;
         }
 
-        w.write_str("</div></details>").unwrap();
+        w.write_str("</div></details>")?;
     }
 
-    w.write_str("</div>").unwrap();
+    w.write_str("</div>")
 }
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index cd0c9775f5c..a9029972d96 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,5 +1,6 @@
 use std::borrow::Cow;
 use std::cmp::Ordering;
+use std::fmt;
 
 use askama::Template;
 use rustc_data_structures::fx::FxHashSet;
@@ -135,7 +136,11 @@ pub(crate) mod filters {
     }
 }
 
-pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut String) {
+pub(super) fn print_sidebar(
+    cx: &Context<'_>,
+    it: &clean::Item,
+    mut buffer: impl fmt::Write,
+) -> fmt::Result {
     let mut ids = IdMap::new();
     let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
     let deref_id_map = cx.deref_id_map.borrow();
@@ -195,7 +200,8 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Str
         blocks,
         path,
     };
-    sidebar.render_into(buffer).unwrap();
+    sidebar.render_into(&mut buffer)?;
+    Ok(())
 }
 
 fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec<Link<'a>> {
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index b2bbf4614bf..4f6e9abdbca 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -611,7 +611,7 @@ impl TypeAliasPart {
                 .impl_
                 .values()
                 .flat_map(|AliasedTypeImpl { impl_, type_aliases }| {
-                    let mut ret = Vec::new();
+                    let mut ret: Vec<AliasSerializableImpl> = Vec::new();
                     let trait_ = impl_
                         .inner_impl()
                         .trait_
@@ -623,42 +623,43 @@ impl TypeAliasPart {
                     for &(type_alias_fqp, type_alias_item) in type_aliases {
                         cx.id_map.borrow_mut().clear();
                         cx.deref_id_map.borrow_mut().clear();
-                        let target_did = impl_
-                            .inner_impl()
-                            .trait_
-                            .as_ref()
-                            .map(|trait_| trait_.def_id())
-                            .or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache));
-                        let provided_methods;
-                        let assoc_link = if let Some(target_did) = target_did {
-                            provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx());
-                            AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods)
-                        } else {
-                            AssocItemLink::Anchor(None)
-                        };
-                        let text = super::render_impl(
-                            cx,
-                            impl_,
-                            type_alias_item,
-                            assoc_link,
-                            RenderMode::Normal,
-                            None,
-                            &[],
-                            ImplRenderingParameters {
-                                show_def_docs: true,
-                                show_default_items: true,
-                                show_non_assoc_items: true,
-                                toggle_open_by_default: true,
-                            },
-                        )
-                        .to_string();
                         let type_alias_fqp = (*type_alias_fqp).iter().join("::");
-                        if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) {
-                            ret.last_mut()
-                                .expect("already established that ret.last() is Some()")
-                                .aliases
-                                .push(type_alias_fqp);
+                        if let Some(last) = ret.last_mut() {
+                            last.aliases.push(type_alias_fqp);
                         } else {
+                            let target_did = impl_
+                                .inner_impl()
+                                .trait_
+                                .as_ref()
+                                .map(|trait_| trait_.def_id())
+                                .or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache));
+                            let provided_methods;
+                            let assoc_link = if let Some(target_did) = target_did {
+                                provided_methods =
+                                    impl_.inner_impl().provided_trait_methods(cx.tcx());
+                                AssocItemLink::GotoSource(
+                                    ItemId::DefId(target_did),
+                                    &provided_methods,
+                                )
+                            } else {
+                                AssocItemLink::Anchor(None)
+                            };
+                            let text = super::render_impl(
+                                cx,
+                                impl_,
+                                type_alias_item,
+                                assoc_link,
+                                RenderMode::Normal,
+                                None,
+                                &[],
+                                ImplRenderingParameters {
+                                    show_def_docs: true,
+                                    show_default_items: true,
+                                    show_non_assoc_items: true,
+                                    toggle_open_by_default: true,
+                                },
+                            )
+                            .to_string();
                             ret.push(AliasSerializableImpl {
                                 text,
                                 trait_: trait_.clone(),
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 095795c711d..1fa6b5a60f3 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -11,9 +11,8 @@ use rustc_session::Session;
 use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym};
 use tracing::info;
 
-use super::highlight;
-use super::layout::{self, BufDisplay};
 use super::render::Context;
+use super::{highlight, layout};
 use crate::clean;
 use crate::clean::utils::has_doc_flag;
 use crate::docfs::PathError;
@@ -243,16 +242,16 @@ impl SourceCollector<'_, '_> {
             &shared.layout,
             &page,
             "",
-            BufDisplay(|buf: &mut String| {
+            fmt::from_fn(|f| {
                 print_src(
-                    buf,
+                    f,
                     contents,
                     file_span,
                     self.cx,
                     &root_path,
                     &highlight::DecorationInfo::default(),
                     &source_context,
-                );
+                )
             }),
             &shared.style_files,
         );
@@ -331,7 +330,7 @@ pub(crate) fn print_src(
     root_path: &str,
     decoration_info: &highlight::DecorationInfo,
     source_context: &SourceContext<'_>,
-) {
+) -> fmt::Result {
     let mut lines = s.lines().count();
     let line_info = if let SourceContext::Embedded(info) = source_context {
         highlight::LineInfo::new_scraped(lines as u32, info.offset as u32)
@@ -367,12 +366,10 @@ pub(crate) fn print_src(
             },
             max_nb_digits,
         }
-        .render_into(&mut writer)
-        .unwrap(),
+        .render_into(&mut writer),
         SourceContext::Embedded(info) => {
-            ScrapedSource { info, code_html: code, max_nb_digits }
-                .render_into(&mut writer)
-                .unwrap();
+            ScrapedSource { info, code_html: code, max_nb_digits }.render_into(&mut writer)
         }
-    };
+    }?;
+    Ok(())
 }
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index a7ce2bf9048..7b1a61a3ffa 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1179,8 +1179,10 @@ function preLoadCss(cssUrl) {
 
     onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
         // @ts-expect-error
+        // Clicking on the summary's contents should not collapse it,
+        // but links within should still fire.
         el.addEventListener("click", e => {
-            if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
+            if (!e.target.matches("summary, a, a *")) {
                 e.preventDefault();
             }
         });
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index f446c9fbbd8..705f9b2202c 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -6,7 +6,7 @@
 
 use rustc_abi::ExternAbi;
 use rustc_ast::ast;
-use rustc_attr_parsing::DeprecatedSince;
+use rustc_attr_data_structures::{self as attrs, DeprecatedSince};
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_metadata::rendered_const;
@@ -153,8 +153,8 @@ where
     }
 }
 
-pub(crate) fn from_deprecation(deprecation: rustc_attr_parsing::Deprecation) -> Deprecation {
-    let rustc_attr_parsing::Deprecation { since, note, suggestion: _ } = deprecation;
+pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation {
+    let attrs::Deprecation { since, note, suggestion: _ } = deprecation;
     let since = match since {
         DeprecatedSince::RustcVersion(version) => Some(version.to_string()),
         DeprecatedSince::Future => Some("TBD".to_owned()),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b4003044e20..025c135aff2 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -3,6 +3,8 @@
     html_playground_url = "https://play.rust-lang.org/"
 )]
 #![feature(rustc_private)]
+#![feature(ascii_char)]
+#![feature(ascii_char_variants)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(debug_closure_helpers)]
@@ -36,6 +38,7 @@ extern crate pulldown_cmark;
 extern crate rustc_abi;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
+extern crate rustc_attr_data_structures;
 extern crate rustc_attr_parsing;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index f3e2138d1a5..37628f16600 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -59,12 +59,7 @@ fn filter_assoc_items_by_name_and_namespace(
     ident: Ident,
     ns: Namespace,
 ) -> impl Iterator<Item = &ty::AssocItem> {
-    let iter: Box<dyn Iterator<Item = &ty::AssocItem>> = if !ident.name.is_empty() {
-        Box::new(tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name))
-    } else {
-        Box::new([].iter())
-    };
-    iter.filter(move |item| {
+    tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
         item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
     })
 }
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index 1e07277d38e..3b3ce3e9220 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -18,12 +18,15 @@ use crate::html::markdown::main_body_opts;
 
 pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
     let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
-        let sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings)
-            .unwrap_or_else(|| item.attr_span(cx.tcx));
+        let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings);
+        let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx));
         cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
             lint.primary_message(msg)
-                .note("bare URLs are not automatically turned into clickable links")
-                .multipart_suggestion(
+                .note("bare URLs are not automatically turned into clickable links");
+            // The fallback of using the attribute span is suitable for
+            // highlighting where the error is, but not for placing the < and >
+            if let Some(sp) = maybe_sp {
+                lint.multipart_suggestion(
                     "use an automatic link instead",
                     vec![
                         (sp.shrink_to_lo(), "<".to_string()),
@@ -31,6 +34,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
                     ],
                     Applicability::MachineApplicable,
                 );
+            }
         });
     };
 
diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs
index fdab2b08779..7b3da8d7c0f 100644
--- a/src/librustdoc/passes/propagate_stability.rs
+++ b/src/librustdoc/passes/propagate_stability.rs
@@ -6,7 +6,7 @@
 //! [`core::error`] module is marked as stable since 1.81.0, so we want to show
 //! [`core::error::Error`] as stable since 1.81.0 as well.
 
-use rustc_attr_parsing::{Stability, StabilityLevel};
+use rustc_attr_data_structures::{Stability, StabilityLevel};
 use rustc_hir::def_id::CRATE_DEF_ID;
 
 use crate::clean::{Crate, Item, ItemId, ItemKind};
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 64223b5b758..c091c955ed5 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
 /// This integer is incremented with every breaking change to the API,
 /// and is returned along with the JSON blob as [`Crate::format_version`].
 /// Consuming code should assert that this value matches the format version(s) that it supports.
-pub const FORMAT_VERSION: u32 = 45;
+pub const FORMAT_VERSION: u32 = 46;
 
 /// The root of the emitted JSON blob.
 ///
@@ -180,19 +180,13 @@ pub struct Item {
     ///
     /// Does not include `#[deprecated]` attributes: see the [`Self::deprecation`] field instead.
     ///
-    /// Some attributes appear in pretty-printed Rust form, regardless of their formatting
+    /// Attributes appear in pretty-printed Rust form, regardless of their formatting
     /// in the original source code. For example:
     /// - `#[non_exhaustive]` and `#[must_use]` are represented as themselves.
     /// - `#[no_mangle]` and `#[export_name]` are also represented as themselves.
     /// - `#[repr(C)]` and other reprs also appear as themselves,
     ///   though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`.
     ///   Multiple repr attributes on the same item may be combined into an equivalent single attr.
-    ///
-    /// Other attributes may appear debug-printed. For example:
-    /// - `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`.
-    ///
-    /// As an internal implementation detail subject to change, this debug-printing format
-    /// is currently equivalent to the HIR pretty-printing of parsed attributes.
     pub attrs: Vec<String>,
     /// Information about the item’s deprecation, if present.
     pub deprecation: Option<Deprecation>,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 47c911e9e6f6461f90ce19142031fe16876a3b9
+Subproject 68db37499f2de8acef704c73d9031be6fbcbaee
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 28147dfbea3..3a98217f625 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6440,6 +6440,7 @@ Released 2018-09-13
 [`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
 [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
+[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat
 [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 45ba2f078be..72ab08792d3 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -51,7 +51,7 @@ Clippy team directly by mentioning them in the issue or over on [Zulip]. All
 currently active team members can be found
 [here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18)
 
-Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy
+Some issues are easier than others. The [`good first issue`] label can be used to find the easy
 issues. You can use `@rustbot claim` to assign the issue to yourself.
 
 There are also some abandoned PRs, marked with [`S-inactive-closed`].
@@ -70,7 +70,7 @@ To figure out how this syntax structure is encoded in the AST, it is recommended
 Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 But we can make it nest-less by using [let chains], [like this][nest-less].
 
-[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
+[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`]
 first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
 Note that [`E-medium`] issues may require some knowledge of Clippy internals or some
 debugging to find the actual problem behind the issue.
@@ -79,7 +79,7 @@ debugging to find the actual problem behind the issue.
 lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
 an AST expression).
 
-[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
+[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue
 [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
 [`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
 [`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index c7c06afb612..f69e5bee4bb 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index cdbbe76bdb0..fc405249bcf 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -151,7 +151,7 @@ toolchain called `clippy` by default, see `cargo dev setup toolchain --help`
 for other options.
 
 ```terminal
-cargo dev setup toolcahin
+cargo dev setup toolchain
 ```
 
 Now you may run `cargo +clippy clippy` in any project using the new toolchain.
diff --git a/src/tools/clippy/book/src/development/the_team.md b/src/tools/clippy/book/src/development/the_team.md
index da5d084ed97..d2212323186 100644
--- a/src/tools/clippy/book/src/development/the_team.md
+++ b/src/tools/clippy/book/src/development/the_team.md
@@ -33,7 +33,7 @@ this group to help with triaging, which can include:
 
 1. **Labeling issues**
 
-    For the `good-first-issue` label, it can still be good to use `@rustbot` to
+    For the `good first issue` label, it can still be good to use `@rustbot` to
     subscribe to the issue and help interested parties, if they post questions
     in the comments. 
 
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 0db4182dbcd..9809e32de8a 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
 * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
 * [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
+* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation)
 * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
 * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
 * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 1134b0e97af..0606245f990 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_config"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 edition = "2024"
 publish = false
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index ad0aea39d41..4ce8d001c2f 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -739,6 +739,7 @@ define_Conf! {
         manual_repeat_n,
         manual_retain,
         manual_slice_fill,
+        manual_slice_size_calculation,
         manual_split_once,
         manual_str_repeat,
         manual_strip,
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 47b7b375861..10c08dba50b 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -5,13 +5,11 @@ version = "0.0.1"
 edition = "2024"
 
 [dependencies]
-aho-corasick = "1.0"
 chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
 clap = { version = "4.4", features = ["derive"] }
 indoc = "1.0"
 itertools = "0.12"
 opener = "0.7"
-shell-escape = "0.1"
 walkdir = "2.3"
 
 [package.metadata.rust-analyzer]
diff --git a/src/tools/clippy/clippy_dev/src/deprecate_lint.rs b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
index bf0e7771046..3bdc5b27723 100644
--- a/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
@@ -1,6 +1,4 @@
-use crate::update_lints::{
-    DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints,
-};
+use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints};
 use crate::utils::{UpdateMode, Version};
 use std::ffi::OsStr;
 use std::path::{Path, PathBuf};
@@ -16,28 +14,34 @@ use std::{fs, io};
 ///
 /// If a file path could not read from or written to
 pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
-    let prefixed_name = if name.starts_with("clippy::") {
-        name.to_owned()
-    } else {
-        format!("clippy::{name}")
-    };
-    let stripped_name = &prefixed_name[8..];
+    if let Some((prefix, _)) = name.split_once("::") {
+        panic!("`{name}` should not contain the `{prefix}` prefix");
+    }
 
     let mut lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed: renamed_lints,
-        deprecated: mut deprecated_lints,
-        file: mut deprecated_file,
-        contents: mut deprecated_contents,
-        deprecated_end,
-        ..
-    } = read_deprecated_lints();
-
-    let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else {
+    let (mut deprecated_lints, renamed_lints) = read_deprecated_lints();
+
+    let Some(lint) = lints.iter().find(|l| l.name == name) else {
         eprintln!("error: failed to find lint `{name}`");
         return;
     };
 
+    let prefixed_name = String::from_iter(["clippy::", name]);
+    match deprecated_lints.binary_search_by(|x| x.name.cmp(&prefixed_name)) {
+        Ok(_) => {
+            println!("`{name}` is already deprecated");
+            return;
+        },
+        Err(idx) => deprecated_lints.insert(
+            idx,
+            DeprecatedLint {
+                name: prefixed_name,
+                reason: reason.into(),
+                version: clippy_version.rust_display().to_string(),
+            },
+        ),
+    }
+
     let mod_path = {
         let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
         if mod_path.is_dir() {
@@ -48,24 +52,7 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
         mod_path
     };
 
-    if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) {
-        deprecated_contents.insert_str(
-            deprecated_end as usize,
-            &format!(
-                "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                clippy_version.rust_display(),
-                prefixed_name,
-                reason,
-            ),
-        );
-        deprecated_file.replace_contents(deprecated_contents.as_bytes());
-        drop(deprecated_file);
-
-        deprecated_lints.push(DeprecatedLint {
-            name: prefixed_name,
-            reason: reason.into(),
-        });
-
+    if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) {
         generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
         println!("info: `{name}` has successfully been deprecated");
         println!("note: you must run `cargo uitest` to update the test results");
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index b4c13213f55..13d6b1285dc 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,19 +1,18 @@
+use crate::utils::{
+    ClippyInfo, ErrAction, FileUpdater, UpdateMode, UpdateStatus, panic_action, run_with_args_split, run_with_output,
+};
 use itertools::Itertools;
 use rustc_lexer::{TokenKind, tokenize};
-use shell_escape::escape;
-use std::ffi::{OsStr, OsString};
+use std::fmt::Write;
+use std::fs;
+use std::io::{self, Read};
 use std::ops::ControlFlow;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
-use std::{fs, io};
 use walkdir::WalkDir;
 
 pub enum Error {
-    CommandFailed(String, String),
     Io(io::Error),
-    RustfmtNotInstalled,
-    WalkDir(walkdir::Error),
-    IntellijSetupActive,
     Parse(PathBuf, usize, String),
     CheckFailed,
 }
@@ -24,37 +23,15 @@ impl From<io::Error> for Error {
     }
 }
 
-impl From<walkdir::Error> for Error {
-    fn from(error: walkdir::Error) -> Self {
-        Self::WalkDir(error)
-    }
-}
-
 impl Error {
     fn display(&self) {
         match self {
             Self::CheckFailed => {
                 eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
             },
-            Self::CommandFailed(command, stderr) => {
-                eprintln!("error: command `{command}` failed!\nstderr: {stderr}");
-            },
             Self::Io(err) => {
                 eprintln!("error: {err}");
             },
-            Self::RustfmtNotInstalled => {
-                eprintln!("error: rustfmt nightly is not installed.");
-            },
-            Self::WalkDir(err) => {
-                eprintln!("error: {err}");
-            },
-            Self::IntellijSetupActive => {
-                eprintln!(
-                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
-                    Not formatting because that would format the local repo as well!\n\
-                    Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
-                );
-            },
             Self::Parse(path, line, msg) => {
                 eprintln!("error parsing `{}:{line}`: {msg}", path.display());
             },
@@ -62,12 +39,6 @@ impl Error {
     }
 }
 
-struct FmtContext {
-    check: bool,
-    verbose: bool,
-    rustfmt_path: String,
-}
-
 struct ClippyConf<'a> {
     name: &'a str,
     attrs: &'a str,
@@ -257,155 +228,153 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
     Ok(())
 }
 
-fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
-    // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
-    // format because rustfmt would also format the entire rustc repo as it is a local
-    // dependency
-    if fs::read_to_string("Cargo.toml")
-        .expect("Failed to read clippy Cargo.toml")
-        .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
-    {
-        return Err(Error::IntellijSetupActive);
-    }
-
-    check_for_rustfmt(context)?;
-
-    cargo_fmt(context, ".".as_ref())?;
-    cargo_fmt(context, "clippy_dev".as_ref())?;
-    cargo_fmt(context, "rustc_tools_util".as_ref())?;
-    cargo_fmt(context, "lintcheck".as_ref())?;
-
-    let chunks = WalkDir::new("tests")
-        .into_iter()
-        .filter_map(|entry| {
-            let entry = entry.expect("failed to find tests");
-            let path = entry.path();
-            if path.extension() != Some("rs".as_ref())
-                || path
-                    .components()
-                    .nth_back(1)
-                    .is_some_and(|c| c.as_os_str() == "syntax-error-recovery")
-                || entry.file_name() == "ice-3891.rs"
-            {
-                None
+/// Format the symbols list
+fn fmt_syms(update_mode: UpdateMode) {
+    FileUpdater::default().update_file_checked(
+        "cargo dev fmt",
+        update_mode,
+        "clippy_utils/src/sym.rs",
+        &mut |_, text: &str, new_text: &mut String| {
+            let (pre, conf) = text.split_once("generate! {\n").expect("can't find generate! call");
+            let (conf, post) = conf.split_once("\n}\n").expect("can't find end of generate! call");
+            let mut lines = conf
+                .lines()
+                .map(|line| {
+                    let line = line.trim();
+                    line.strip_suffix(',').unwrap_or(line).trim_end()
+                })
+                .collect::<Vec<_>>();
+            lines.sort_unstable();
+            write!(
+                new_text,
+                "{pre}generate! {{\n    {},\n}}\n{post}",
+                lines.join(",\n    "),
+            )
+            .unwrap();
+            if text == new_text {
+                UpdateStatus::Unchanged
             } else {
-                Some(entry.into_path().into_os_string())
+                UpdateStatus::Changed
             }
-        })
-        .chunks(250);
-
-    for chunk in &chunks {
-        rustfmt(context, chunk)?;
-    }
-    Ok(())
+        },
+    );
 }
 
-// the "main" function of cargo dev fmt
-pub fn run(check: bool, verbose: bool) {
-    let output = Command::new("rustup")
-        .args(["which", "rustfmt"])
-        .stderr(Stdio::inherit())
-        .output()
-        .expect("error running `rustup which rustfmt`");
-    if !output.status.success() {
-        eprintln!("`rustup which rustfmt` did not execute successfully");
-        process::exit(1);
-    }
-    let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path");
+fn run_rustfmt(clippy: &ClippyInfo, update_mode: UpdateMode) {
+    let mut rustfmt_path = String::from_utf8(run_with_output(
+        "rustup which rustfmt",
+        Command::new("rustup").args(["which", "rustfmt"]),
+    ))
+    .expect("invalid rustfmt path");
     rustfmt_path.truncate(rustfmt_path.trim_end().len());
 
-    let context = FmtContext {
-        check,
-        verbose,
-        rustfmt_path,
-    };
-    if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) {
-        e.display();
-        process::exit(1);
-    }
-}
-
-fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
-    let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect();
-
-    format!(
-        "cd {} && {} {}",
-        escape(dir.as_ref().to_string_lossy()),
-        escape(program.as_ref().to_string_lossy()),
-        arg_display.join(" ")
-    )
-}
-
-fn exec_fmt_command(
-    context: &FmtContext,
-    program: impl AsRef<OsStr>,
-    dir: impl AsRef<Path>,
-    args: &[impl AsRef<OsStr>],
-) -> Result<(), Error> {
-    if context.verbose {
-        println!("{}", format_command(&program, &dir, args));
+    let mut cargo_path = String::from_utf8(run_with_output(
+        "rustup which cargo",
+        Command::new("rustup").args(["which", "cargo"]),
+    ))
+    .expect("invalid cargo path");
+    cargo_path.truncate(cargo_path.trim_end().len());
+
+    // Start all format jobs first before waiting on the results.
+    let mut children = Vec::with_capacity(16);
+    for &path in &[
+        ".",
+        "clippy_config",
+        "clippy_dev",
+        "clippy_lints",
+        "clippy_lints_internal",
+        "clippy_utils",
+        "rustc_tools_util",
+        "lintcheck",
+    ] {
+        let mut cmd = Command::new(&cargo_path);
+        cmd.current_dir(clippy.path.join(path))
+            .args(["fmt"])
+            .env("RUSTFMT", &rustfmt_path)
+            .stdout(Stdio::null())
+            .stdin(Stdio::null())
+            .stderr(Stdio::piped());
+        if update_mode.is_check() {
+            cmd.arg("--check");
+        }
+        match cmd.spawn() {
+            Ok(x) => children.push(("cargo fmt", x)),
+            Err(ref e) => panic_action(&e, ErrAction::Run, "cargo fmt".as_ref()),
+        }
     }
 
-    let output = Command::new(&program)
-        .env("RUSTFMT", &context.rustfmt_path)
-        .current_dir(&dir)
-        .args(args.iter())
-        .output()
-        .unwrap();
-    let success = output.status.success();
-
-    match (context.check, success) {
-        (_, true) => Ok(()),
-        (true, false) => Err(Error::CheckFailed),
-        (false, false) => {
-            let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
-            Err(Error::CommandFailed(
-                format_command(&program, &dir, args),
-                String::from(stderr),
-            ))
+    run_with_args_split(
+        || {
+            let mut cmd = Command::new(&rustfmt_path);
+            if update_mode.is_check() {
+                cmd.arg("--check");
+            }
+            cmd.stdout(Stdio::null())
+                .stdin(Stdio::null())
+                .stderr(Stdio::piped())
+                .args(["--config", "show_parse_errors=false"]);
+            cmd
         },
-    }
-}
+        |cmd| match cmd.spawn() {
+            Ok(x) => children.push(("rustfmt", x)),
+            Err(ref e) => panic_action(&e, ErrAction::Run, "rustfmt".as_ref()),
+        },
+        WalkDir::new("tests")
+            .into_iter()
+            .filter_entry(|p| p.path().file_name().is_none_or(|x| x != "skip_rustfmt"))
+            .filter_map(|e| {
+                let e = e.expect("error reading `tests`");
+                e.path()
+                    .as_os_str()
+                    .as_encoded_bytes()
+                    .ends_with(b".rs")
+                    .then(|| e.into_path().into_os_string())
+            }),
+    );
 
-fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> {
-    let mut args = vec!["fmt", "--all"];
-    if context.check {
-        args.push("--check");
+    for (name, child) in &mut children {
+        match child.wait() {
+            Ok(status) => match (update_mode, status.exit_ok()) {
+                (UpdateMode::Check | UpdateMode::Change, Ok(())) => {},
+                (UpdateMode::Check, Err(_)) => {
+                    let mut s = String::new();
+                    if let Some(mut stderr) = child.stderr.take()
+                        && stderr.read_to_string(&mut s).is_ok()
+                    {
+                        eprintln!("{s}");
+                    }
+                    eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
+                    process::exit(1);
+                },
+                (UpdateMode::Change, Err(e)) => {
+                    let mut s = String::new();
+                    if let Some(mut stderr) = child.stderr.take()
+                        && stderr.read_to_string(&mut s).is_ok()
+                    {
+                        eprintln!("{s}");
+                    }
+                    panic_action(&e, ErrAction::Run, name.as_ref());
+                },
+            },
+            Err(ref e) => panic_action(e, ErrAction::Run, name.as_ref()),
+        }
     }
-    exec_fmt_command(context, "cargo", path, &args)
 }
 
-fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> {
-    let program = "rustfmt";
-    let dir = std::env::current_dir()?;
-    let args = &["--version"];
-
-    if context.verbose {
-        println!("{}", format_command(program, &dir, args));
-    }
-
-    let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?;
-
-    if output.status.success() {
-        Ok(())
-    } else if std::str::from_utf8(&output.stderr)
-        .unwrap_or("")
-        .starts_with("error: 'rustfmt' is not installed")
-    {
-        Err(Error::RustfmtNotInstalled)
-    } else {
-        Err(Error::CommandFailed(
-            format_command(program, &dir, args),
-            std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
-        ))
+// the "main" function of cargo dev fmt
+pub fn run(clippy: &ClippyInfo, update_mode: UpdateMode) {
+    if clippy.has_intellij_hook {
+        eprintln!(
+            "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
+            Not formatting because that would format the local repo as well!\n\
+            Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
+        );
+        return;
     }
-}
-
-fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<(), Error> {
-    let mut args = Vec::new();
-    if context.check {
-        args.push(OsString::from("--check"));
+    run_rustfmt(clippy, update_mode);
+    fmt_syms(update_mode);
+    if let Err(e) = fmt_conf(update_mode.is_check()) {
+        e.display();
+        process::exit(1);
     }
-    args.extend(paths);
-    exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args)
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index e237a05b253..3361443196a 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,4 +1,12 @@
-#![feature(rustc_private, if_let_guard, let_chains)]
+#![feature(
+    rustc_private,
+    exit_status_error,
+    if_let_guard,
+    let_chains,
+    os_str_slice,
+    os_string_truncate,
+    slice_split_once
+)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 5dce0be742b..ebcd8611d78 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -26,7 +26,7 @@ fn main() {
             allow_staged,
             allow_no_vcs,
         } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
-        DevCommand::Fmt { check, verbose } => fmt::run(check, verbose),
+        DevCommand::Fmt { check } => fmt::run(&clippy, utils::UpdateMode::from_check(check)),
         DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)),
         DevCommand::NewLint {
             pass,
@@ -125,9 +125,6 @@ enum DevCommand {
         #[arg(long)]
         /// Use the rustfmt --check option
         check: bool,
-        #[arg(short, long)]
-        /// Echo commands run
-        verbose: bool,
     },
     #[command(name = "update_lints")]
     /// Updates lint registration and information from the source code
diff --git a/src/tools/clippy/clippy_dev/src/release.rs b/src/tools/clippy/clippy_dev/src/release.rs
index d3b1a7ff320..62c1bee8185 100644
--- a/src/tools/clippy/clippy_dev/src/release.rs
+++ b/src/tools/clippy/clippy_dev/src/release.rs
@@ -1,4 +1,4 @@
-use crate::utils::{FileUpdater, Version, update_text_region_fn};
+use crate::utils::{FileUpdater, UpdateStatus, Version, parse_cargo_package};
 use std::fmt::Write;
 
 static CARGO_TOML_FILES: &[&str] = &[
@@ -13,15 +13,17 @@ pub fn bump_version(mut version: Version) {
 
     let mut updater = FileUpdater::default();
     for file in CARGO_TOML_FILES {
-        updater.update_file(
-            file,
-            &mut update_text_region_fn(
-                "# begin autogenerated version\n",
-                "# end autogenerated version",
-                |dst| {
-                    writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap();
-                },
-            ),
-        );
+        updater.update_file(file, &mut |_, src, dst| {
+            let package = parse_cargo_package(src);
+            if package.version_range.is_empty() {
+                dst.push_str(src);
+                UpdateStatus::Unchanged
+            } else {
+                dst.push_str(&src[..package.version_range.start]);
+                write!(dst, "\"{}\"", version.toml_display()).unwrap();
+                dst.push_str(&src[package.version_range.end..]);
+                UpdateStatus::from_changed(src.get(package.version_range.clone()) != dst.get(package.version_range))
+            }
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/rename_lint.rs b/src/tools/clippy/clippy_dev/src/rename_lint.rs
index 9e7e5d97f02..be8b27c7a9e 100644
--- a/src/tools/clippy/clippy_dev/src/rename_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/rename_lint.rs
@@ -1,9 +1,11 @@
-use crate::update_lints::{
-    DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files,
-    read_deprecated_lints,
+use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints};
+use crate::utils::{
+    FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists,
+    try_rename_dir, try_rename_file,
 };
-use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file};
-use std::ffi::OsStr;
+use rustc_lexer::TokenKind;
+use std::ffi::OsString;
+use std::fs;
 use std::path::Path;
 use walkdir::WalkDir;
 
@@ -22,7 +24,7 @@ use walkdir::WalkDir;
 /// * If either lint name has a prefix
 /// * If `old_name` doesn't name an existing lint.
 /// * If `old_name` names a deprecated or renamed lint.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) {
     if let Some((prefix, _)) = old_name.split_once("::") {
         panic!("`{old_name}` should not contain the `{prefix}` prefix");
@@ -33,162 +35,369 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
 
     let mut updater = FileUpdater::default();
     let mut lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed: mut renamed_lints,
-        deprecated: deprecated_lints,
-        file: mut deprecated_file,
-        contents: mut deprecated_contents,
-        renamed_end,
-        ..
-    } = read_deprecated_lints();
-
-    let mut old_lint_index = None;
-    let mut found_new_name = false;
-    for (i, lint) in lints.iter().enumerate() {
-        if lint.name == old_name {
-            old_lint_index = Some(i);
-        } else if lint.name == new_name {
-            found_new_name = true;
+    let (deprecated_lints, mut renamed_lints) = read_deprecated_lints();
+
+    let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else {
+        panic!("could not find lint `{old_name}`");
+    };
+    let lint = &lints[lint_idx];
+
+    let old_name_prefixed = String::from_iter(["clippy::", old_name]);
+    let new_name_prefixed = if uplift {
+        new_name.to_owned()
+    } else {
+        String::from_iter(["clippy::", new_name])
+    };
+
+    for lint in &mut renamed_lints {
+        if lint.new_name == old_name_prefixed {
+            lint.new_name.clone_from(&new_name_prefixed);
         }
     }
-    let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
+    match renamed_lints.binary_search_by(|x| x.old_name.cmp(&old_name_prefixed)) {
+        Ok(_) => {
+            println!("`{old_name}` already has a rename registered");
+            return;
+        },
+        Err(idx) => {
+            renamed_lints.insert(
+                idx,
+                RenamedLint {
+                    old_name: old_name_prefixed,
+                    new_name: if uplift {
+                        new_name.to_owned()
+                    } else {
+                        String::from_iter(["clippy::", new_name])
+                    },
+                    version: clippy_version.rust_display().to_string(),
+                },
+            );
+        },
+    }
 
-    let lint = RenamedLint {
-        old_name: format!("clippy::{old_name}"),
-        new_name: if uplift {
-            new_name.into()
+    // Some tests are named `lint_name_suffix` which should also be renamed,
+    // but we can't do that if the renamed lint's name overlaps with another
+    // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists.
+    let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name));
+
+    let mut mod_edit = ModEdit::None;
+    if uplift {
+        let is_unique_mod = lints[..lint_idx].iter().any(|l| l.module == lint.module)
+            || lints[lint_idx + 1..].iter().any(|l| l.module == lint.module);
+        if is_unique_mod {
+            if delete_file_if_exists(lint.path.as_ref()) {
+                mod_edit = ModEdit::Delete;
+            }
         } else {
-            format!("clippy::{new_name}")
-        },
-    };
+            updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus {
+                let mut start = &src[..lint.declaration_range.start];
+                if start.ends_with("\n\n") {
+                    start = &start[..start.len() - 1];
+                }
+                let mut end = &src[lint.declaration_range.end..];
+                if end.starts_with("\n\n") {
+                    end = &end[1..];
+                }
+                dst.push_str(start);
+                dst.push_str(end);
+                UpdateStatus::Changed
+            });
+        }
+        delete_test_files(old_name, change_prefixed_tests);
+        lints.remove(lint_idx);
+    } else if lints.binary_search_by(|x| x.name.as_str().cmp(new_name)).is_err() {
+        let lint = &mut lints[lint_idx];
+        if lint.module.ends_with(old_name)
+            && lint
+                .path
+                .file_stem()
+                .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes())
+        {
+            let mut new_path = lint.path.with_file_name(new_name).into_os_string();
+            new_path.push(".rs");
+            if try_rename_file(lint.path.as_ref(), new_path.as_ref()) {
+                mod_edit = ModEdit::Rename;
+            }
 
-    // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in
-    // case.
-    assert!(
-        !renamed_lints.iter().any(|l| lint.old_name == l.old_name),
-        "`{old_name}` has already been renamed"
-    );
-    assert!(
-        !deprecated_lints.iter().any(|l| lint.old_name == l.name),
-        "`{old_name}` has already been deprecated"
-    );
-
-    // Update all lint level attributes. (`clippy::lint_name`)
-    let replacements = &[(&*lint.old_name, &*lint.new_name)];
-    let replacer = StringReplacer::new(replacements);
-    for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| {
-        let name = f.path().file_name();
-        let ext = f.path().extension();
-        (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
-            && name != Some(OsStr::new("rename.rs"))
-            && name != Some(OsStr::new("deprecated_lints.rs"))
-    }) {
-        updater.update_file(file.path(), &mut replacer.replace_ident_fn());
+            let mod_len = lint.module.len();
+            lint.module.truncate(mod_len - old_name.len());
+            lint.module.push_str(new_name);
+        }
+        rename_test_files(old_name, new_name, change_prefixed_tests);
+        new_name.clone_into(&mut lints[lint_idx].name);
+        lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
+    } else {
+        println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`");
+        println!("Since `{new_name}` already exists the existing code has not been changed");
+        return;
     }
 
-    deprecated_contents.insert_str(
-        renamed_end as usize,
-        &format!(
-            "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-            clippy_version.rust_display(),
-            lint.old_name,
-            lint.new_name,
-        ),
-    );
-    deprecated_file.replace_contents(deprecated_contents.as_bytes());
-    drop(deprecated_file);
-
-    renamed_lints.push(lint);
-    renamed_lints.sort_by(|lhs, rhs| {
-        lhs.new_name
-            .starts_with("clippy::")
-            .cmp(&rhs.new_name.starts_with("clippy::"))
-            .reverse()
-            .then_with(|| lhs.old_name.cmp(&rhs.old_name))
-    });
+    let mut update_fn = file_update_fn(old_name, new_name, mod_edit);
+    for file in WalkDir::new(".").into_iter().filter_entry(|e| {
+        // Skip traversing some of the larger directories.
+        e.path()
+            .as_os_str()
+            .as_encoded_bytes()
+            .get(2..)
+            .is_none_or(|x| x != "target".as_bytes() && x != ".git".as_bytes())
+    }) {
+        let file = file.expect("error reading clippy directory");
+        if file.path().as_os_str().as_encoded_bytes().ends_with(b".rs") {
+            updater.update_file(file.path(), &mut update_fn);
+        }
+    }
+    generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
 
     if uplift {
-        updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints));
-        println!(
-            "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually."
-        );
-    } else if found_new_name {
-        updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints));
-        println!(
-            "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually."
-        );
-    } else {
-        // Rename the lint struct and source files sharing a name with the lint.
-        let lint = &mut lints[old_lint_index];
-        let old_name_upper = old_name.to_uppercase();
-        let new_name_upper = new_name.to_uppercase();
-        lint.name = new_name.into();
-
-        // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist.
-        if try_rename_file(
-            Path::new(&format!("tests/ui/{old_name}.rs")),
-            Path::new(&format!("tests/ui/{new_name}.rs")),
-        ) {
-            try_rename_file(
-                Path::new(&format!("tests/ui/{old_name}.stderr")),
-                Path::new(&format!("tests/ui/{new_name}.stderr")),
-            );
-            try_rename_file(
-                Path::new(&format!("tests/ui/{old_name}.fixed")),
-                Path::new(&format!("tests/ui/{new_name}.fixed")),
-            );
+        println!("Uplifted `clippy::{old_name}` as `{new_name}`");
+        if matches!(mod_edit, ModEdit::None) {
+            println!("Only the rename has been registered, the code will need to be edited manually");
+        } else {
+            println!("All the lint's code has been deleted");
+            println!("Make sure to inspect the results as some things may have been missed");
         }
+    } else {
+        println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`");
+        println!("All code referencing the old name has been updated");
+        println!("Make sure to inspect the results as some things may have been missed");
+    }
+    println!("note: `cargo uibless` still needs to be run to update the test results");
+}
+
+#[derive(Clone, Copy)]
+enum ModEdit {
+    None,
+    Delete,
+    Rename,
+}
 
-        // Try to rename the file containing the lint if the file name matches the lint's name.
-        let replacements;
-        let replacements = if lint.module == old_name
-            && try_rename_file(
-                Path::new(&format!("clippy_lints/src/{old_name}.rs")),
-                Path::new(&format!("clippy_lints/src/{new_name}.rs")),
-            ) {
-            // Edit the module name in the lint list. Note there could be multiple lints.
-            for lint in lints.iter_mut().filter(|l| l.module == old_name) {
-                lint.module = new_name.into();
+fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) {
+    for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") {
+        let e = e.expect("error reading `tests/ui`");
+        let name = e.file_name();
+        if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') {
+            if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) {
+                dst.push((name, true));
             }
-            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
-            replacements.as_slice()
-        } else if !lint.module.contains("::")
-            // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs`
-            && try_rename_file(
-                Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)),
-                Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)),
-            )
+        } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len())
         {
-            // Edit the module name in the lint list. Note there could be multiple lints, or none.
-            let renamed_mod = format!("{}::{old_name}", lint.module);
-            for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) {
-                lint.module = format!("{}::{new_name}", lint.module);
+            dst.push((name, false));
+        }
+    }
+}
+
+fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) {
+    if rename_prefixed {
+        for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") {
+            let e = e.expect("error reading `tests/ui-toml`");
+            let name = e.file_name();
+            if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) {
+                dst.push((name, false));
             }
-            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
-            replacements.as_slice()
+        }
+    } else {
+        dst.push((lint.into(), false));
+    }
+}
+
+/// Renames all test files for the given lint.
+///
+/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix.
+fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) {
+    let mut tests = Vec::new();
+
+    let mut old_buf = OsString::from("tests/ui/");
+    let mut new_buf = OsString::from("tests/ui/");
+    collect_ui_test_names(old_name, rename_prefixed, &mut tests);
+    for &(ref name, is_file) in &tests {
+        old_buf.push(name);
+        new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]);
+        if is_file {
+            try_rename_file(old_buf.as_ref(), new_buf.as_ref());
         } else {
-            replacements = [(&*old_name_upper, &*new_name_upper), ("", "")];
-            &replacements[0..1]
-        };
-
-        // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
-        // renamed.
-        let replacer = StringReplacer::new(replacements);
-        for file in WalkDir::new("clippy_lints/src") {
-            let file = file.expect("error reading `clippy_lints/src`");
-            if file
-                .path()
-                .as_os_str()
-                .to_str()
-                .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs")
-            {
-                updater.update_file(file.path(), &mut replacer.replace_ident_fn());
-            }
+            try_rename_dir(old_buf.as_ref(), new_buf.as_ref());
+        }
+        old_buf.truncate("tests/ui/".len());
+        new_buf.truncate("tests/ui/".len());
+    }
+
+    tests.clear();
+    old_buf.truncate("tests/ui".len());
+    new_buf.truncate("tests/ui".len());
+    old_buf.push("-toml/");
+    new_buf.push("-toml/");
+    collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests);
+    for (name, _) in &tests {
+        old_buf.push(name);
+        new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]);
+        try_rename_dir(old_buf.as_ref(), new_buf.as_ref());
+        old_buf.truncate("tests/ui/".len());
+        new_buf.truncate("tests/ui/".len());
+    }
+}
+
+fn delete_test_files(lint: &str, rename_prefixed: bool) {
+    let mut tests = Vec::new();
+
+    let mut buf = OsString::from("tests/ui/");
+    collect_ui_test_names(lint, rename_prefixed, &mut tests);
+    for &(ref name, is_file) in &tests {
+        buf.push(name);
+        if is_file {
+            delete_file_if_exists(buf.as_ref());
+        } else {
+            delete_dir_if_exists(buf.as_ref());
         }
+        buf.truncate("tests/ui/".len());
+    }
 
-        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
-        println!("{old_name} has been successfully renamed");
+    buf.truncate("tests/ui".len());
+    buf.push("-toml/");
+
+    tests.clear();
+    collect_ui_toml_test_names(lint, rename_prefixed, &mut tests);
+    for (name, _) in &tests {
+        buf.push(name);
+        delete_dir_if_exists(buf.as_ref());
+        buf.truncate("tests/ui/".len());
     }
+}
 
-    println!("note: `cargo uitest` still needs to be run to update the test results");
+fn snake_to_pascal(s: &str) -> String {
+    let mut dst = Vec::with_capacity(s.len());
+    let mut iter = s.bytes();
+    || -> Option<()> {
+        dst.push(iter.next()?.to_ascii_uppercase());
+        while let Some(c) = iter.next() {
+            if c == b'_' {
+                dst.push(iter.next()?.to_ascii_uppercase());
+            } else {
+                dst.push(c);
+            }
+        }
+        Some(())
+    }();
+    String::from_utf8(dst).unwrap()
+}
+
+#[expect(clippy::too_many_lines)]
+fn file_update_fn<'a, 'b>(
+    old_name: &'a str,
+    new_name: &'b str,
+    mod_edit: ModEdit,
+) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus {
+    let old_name_pascal = snake_to_pascal(old_name);
+    let new_name_pascal = snake_to_pascal(new_name);
+    let old_name_upper = old_name.to_ascii_uppercase();
+    let new_name_upper = new_name.to_ascii_uppercase();
+    move |_, src, dst| {
+        let mut copy_pos = 0u32;
+        let mut changed = false;
+        let mut searcher = RustSearcher::new(src);
+        let mut capture = "";
+        loop {
+            match searcher.peek() {
+                TokenKind::Eof => break,
+                TokenKind::Ident => {
+                    let match_start = searcher.pos();
+                    let text = searcher.peek_text();
+                    searcher.step();
+                    match text {
+                        // clippy::line_name or clippy::lint-name
+                        "clippy" => {
+                            if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture])
+                                && capture == old_name
+                            {
+                                dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                                dst.push_str(new_name);
+                                copy_pos = searcher.pos();
+                                changed = true;
+                            }
+                        },
+                        // mod lint_name
+                        "mod" => {
+                            if !matches!(mod_edit, ModEdit::None)
+                                && searcher.match_tokens(&[Token::CaptureIdent], &mut [&mut capture])
+                                && capture == old_name
+                            {
+                                match mod_edit {
+                                    ModEdit::Rename => {
+                                        dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                                        dst.push_str(new_name);
+                                        copy_pos = searcher.pos();
+                                        changed = true;
+                                    },
+                                    ModEdit::Delete if searcher.match_tokens(&[Token::Semi], &mut []) => {
+                                        let mut start = &src[copy_pos as usize..match_start as usize];
+                                        if start.ends_with("\n\n") {
+                                            start = &start[..start.len() - 1];
+                                        }
+                                        dst.push_str(start);
+                                        copy_pos = searcher.pos();
+                                        if src[copy_pos as usize..].starts_with("\n\n") {
+                                            copy_pos += 1;
+                                        }
+                                        changed = true;
+                                    },
+                                    ModEdit::Delete | ModEdit::None => {},
+                                }
+                            }
+                        },
+                        // lint_name::
+                        name if matches!(mod_edit, ModEdit::Rename) && name == old_name => {
+                            let name_end = searcher.pos();
+                            if searcher.match_tokens(&[Token::DoubleColon], &mut []) {
+                                dst.push_str(&src[copy_pos as usize..match_start as usize]);
+                                dst.push_str(new_name);
+                                copy_pos = name_end;
+                                changed = true;
+                            }
+                        },
+                        // LINT_NAME or LintName
+                        name => {
+                            let replacement = if name == old_name_upper {
+                                &new_name_upper
+                            } else if name == old_name_pascal {
+                                &new_name_pascal
+                            } else {
+                                continue;
+                            };
+                            dst.push_str(&src[copy_pos as usize..match_start as usize]);
+                            dst.push_str(replacement);
+                            copy_pos = searcher.pos();
+                            changed = true;
+                        },
+                    }
+                },
+                // //~ lint_name
+                TokenKind::LineComment { doc_style: None } => {
+                    let text = searcher.peek_text();
+                    if text.starts_with("//~")
+                        && let Some(text) = text.strip_suffix(old_name)
+                        && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
+                    {
+                        dst.push_str(&src[copy_pos as usize..searcher.pos() as usize + text.len()]);
+                        dst.push_str(new_name);
+                        copy_pos = searcher.pos() + searcher.peek_len();
+                        changed = true;
+                    }
+                    searcher.step();
+                },
+                // ::lint_name
+                TokenKind::Colon
+                    if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture])
+                        && capture == old_name =>
+                {
+                    dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                    dst.push_str(new_name);
+                    copy_pos = searcher.pos();
+                    changed = true;
+                },
+                _ => searcher.step(),
+            }
+        }
+
+        dst.push_str(&src[copy_pos as usize..]);
+        UpdateStatus::from_changed(changed)
+    }
 }
diff --git a/src/tools/clippy/clippy_dev/src/sync.rs b/src/tools/clippy/clippy_dev/src/sync.rs
index c699b0d7b95..98fd72fc0bd 100644
--- a/src/tools/clippy/clippy_dev/src/sync.rs
+++ b/src/tools/clippy/clippy_dev/src/sync.rs
@@ -4,15 +4,22 @@ use std::fmt::Write;
 
 pub fn update_nightly() {
     let date = Utc::now().format("%Y-%m-%d").to_string();
-    let update = &mut update_text_region_fn(
+    let toolchain_update = &mut update_text_region_fn(
         "# begin autogenerated nightly\n",
         "# end autogenerated nightly",
         |dst| {
             writeln!(dst, "channel = \"nightly-{date}\"").unwrap();
         },
     );
+    let readme_update = &mut update_text_region_fn(
+        "<!-- begin autogenerated nightly -->\n",
+        "<!-- end autogenerated nightly -->",
+        |dst| {
+            writeln!(dst, "```\nnightly-{date}\n```").unwrap();
+        },
+    );
 
     let mut updater = FileUpdater::default();
-    updater.update_file("rust-toolchain.toml", update);
-    updater.update_file("clippy_utils/README.md", update);
+    updater.update_file("rust-toolchain.toml", toolchain_update);
+    updater.update_file("clippy_utils/README.md", readme_update);
 }
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 0c861b72935..25ba2c72049 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,12 +1,11 @@
 use crate::utils::{
-    File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn,
+    ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_action, update_text_region_fn,
 };
 use itertools::Itertools;
 use std::collections::HashSet;
 use std::fmt::Write;
-use std::fs::OpenOptions;
 use std::ops::Range;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
 
 const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -26,12 +25,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht
 /// Panics if a file path could not read from or then written to
 pub fn update(update_mode: UpdateMode) {
     let lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed, deprecated, ..
-    } = read_deprecated_lints();
+    let (deprecated, renamed) = read_deprecated_lints();
     generate_lint_files(update_mode, &lints, &deprecated, &renamed);
 }
 
+#[expect(clippy::too_many_lines)]
 pub fn generate_lint_files(
     update_mode: UpdateMode,
     lints: &[Lint],
@@ -93,6 +91,40 @@ pub fn generate_lint_files(
                 dst.push_str("];\n");
                 UpdateStatus::from_changed(src != dst)
             }),
+            ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| {
+                let mut searcher = RustSearcher::new(src);
+                assert!(
+                    searcher.find_token(Token::Ident("declare_with_version"))
+                        && searcher.find_token(Token::Ident("declare_with_version")),
+                    "error reading deprecated lints"
+                );
+                dst.push_str(&src[..searcher.pos() as usize]);
+                dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
+                for lint in deprecated {
+                    write!(
+                        dst,
+                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                        lint.version, lint.name, lint.reason,
+                    )
+                    .unwrap();
+                }
+                dst.push_str(
+                    "]}\n\n\
+                    #[rustfmt::skip]\n\
+                    declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\
+                ",
+                );
+                for lint in renamed {
+                    write!(
+                        dst,
+                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                        lint.version, lint.old_name, lint.new_name,
+                    )
+                    .unwrap();
+                }
+                dst.push_str("]}\n");
+                UpdateStatus::from_changed(src != dst)
+            }),
             ("tests/ui/deprecated.rs", &mut |_, src, dst| {
                 dst.push_str(GENERATED_FILE_COMMENT);
                 for lint in deprecated {
@@ -101,7 +133,24 @@ pub fn generate_lint_files(
                 dst.push_str("\nfn main() {}\n");
                 UpdateStatus::from_changed(src != dst)
             }),
-            ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)),
+            ("tests/ui/rename.rs", &mut move |_, src, dst| {
+                let mut seen_lints = HashSet::new();
+                dst.push_str(GENERATED_FILE_COMMENT);
+                dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
+                for lint in renamed {
+                    if seen_lints.insert(&lint.new_name) {
+                        writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
+                    }
+                }
+                seen_lints.clear();
+                for lint in renamed {
+                    if seen_lints.insert(&lint.old_name) {
+                        writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
+                    }
+                }
+                dst.push_str("\nfn main() {}\n");
+                UpdateStatus::from_changed(src != dst)
+            }),
         ],
     );
 }
@@ -111,44 +160,25 @@ fn round_to_fifty(count: usize) -> usize {
 }
 
 /// Lint data parsed from the Clippy source code.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(PartialEq, Eq, Debug)]
 pub struct Lint {
     pub name: String,
     pub group: String,
     pub module: String,
+    pub path: PathBuf,
     pub declaration_range: Range<usize>,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
 pub struct DeprecatedLint {
     pub name: String,
     pub reason: String,
+    pub version: String,
 }
 
 pub struct RenamedLint {
     pub old_name: String,
     pub new_name: String,
-}
-
-pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus {
-    move |_, src, dst| {
-        let mut seen_lints = HashSet::new();
-        dst.push_str(GENERATED_FILE_COMMENT);
-        dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
-        for lint in lints {
-            if seen_lints.insert(&lint.new_name) {
-                writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
-            }
-        }
-        seen_lints.clear();
-        for lint in lints {
-            if seen_lints.insert(&lint.old_name) {
-                writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
-            }
-        }
-        dst.push_str("\nfn main() {}\n");
-        UpdateStatus::from_changed(src != dst)
-    }
+    pub version: String,
 }
 
 /// Finds all lint declarations (`declare_clippy_lint!`)
@@ -158,6 +188,7 @@ pub fn find_lint_decls() -> Vec<Lint> {
     let mut contents = String::new();
     for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
         parse_clippy_lint_decls(
+            file.path(),
             File::open_read_to_cleared_string(file.path(), &mut contents),
             &module,
             &mut lints,
@@ -172,7 +203,7 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
     WalkDir::new(src_root).into_iter().filter_map(move |e| {
         let e = match e {
             Ok(e) => e,
-            Err(ref e) => panic_file(e, FileAction::Read, src_root),
+            Err(ref e) => panic_action(e, ErrAction::Read, src_root),
         };
         let path = e.path().as_os_str().as_encoded_bytes();
         if let Some(path) = path.strip_suffix(b".rs")
@@ -202,17 +233,17 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
 }
 
 /// Parse a source file looking for `declare_clippy_lint` macro invocations.
-fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec<Lint>) {
+fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mut Vec<Lint>) {
     #[allow(clippy::enum_glob_use)]
     use Token::*;
     #[rustfmt::skip]
-    static DECL_TOKENS: &[Token] = &[
+    static DECL_TOKENS: &[Token<'_>] = &[
         // !{ /// docs
-        Bang, OpenBrace, AnyDoc,
+        Bang, OpenBrace, AnyComment,
         // #[clippy::version = "version"]
         Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
         // pub NAME, GROUP,
-        Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma,
+        Ident("pub"), CaptureIdent, Comma, AnyComment, CaptureIdent, Comma,
     ];
 
     let mut searcher = RustSearcher::new(contents);
@@ -224,55 +255,42 @@ fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec<Lint>)
                 name: name.to_lowercase(),
                 group: group.into(),
                 module: module.into(),
+                path: path.into(),
                 declaration_range: start..searcher.pos() as usize,
             });
         }
     }
 }
 
-pub struct DeprecatedLints {
-    pub file: File<'static>,
-    pub contents: String,
-    pub deprecated: Vec<DeprecatedLint>,
-    pub renamed: Vec<RenamedLint>,
-    pub deprecated_end: u32,
-    pub renamed_end: u32,
-}
-
 #[must_use]
-pub fn read_deprecated_lints() -> DeprecatedLints {
+pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
     #[allow(clippy::enum_glob_use)]
     use Token::*;
     #[rustfmt::skip]
-    static DECL_TOKENS: &[Token] = &[
+    static DECL_TOKENS: &[Token<'_>] = &[
         // #[clippy::version = "version"]
-        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
+        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket,
         // ("first", "second"),
         OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma,
     ];
     #[rustfmt::skip]
-    static DEPRECATED_TOKENS: &[Token] = &[
+    static DEPRECATED_TOKENS: &[Token<'_>] = &[
         // !{ DEPRECATED(DEPRECATED_VERSION) = [
         Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket,
     ];
     #[rustfmt::skip]
-    static RENAMED_TOKENS: &[Token] = &[
+    static RENAMED_TOKENS: &[Token<'_>] = &[
         // !{ RENAMED(RENAMED_VERSION) = [
         Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket,
     ];
 
     let path = "clippy_lints/src/deprecated_lints.rs";
-    let mut res = DeprecatedLints {
-        file: File::open(path, OpenOptions::new().read(true).write(true)),
-        contents: String::new(),
-        deprecated: Vec::with_capacity(30),
-        renamed: Vec::with_capacity(80),
-        deprecated_end: 0,
-        renamed_end: 0,
-    };
+    let mut deprecated = Vec::with_capacity(30);
+    let mut renamed = Vec::with_capacity(80);
+    let mut contents = String::new();
+    File::open_read_to_cleared_string(path, &mut contents);
 
-    res.file.read_append_to_string(&mut res.contents);
-    let mut searcher = RustSearcher::new(&res.contents);
+    let mut searcher = RustSearcher::new(&contents);
 
     // First instance is the macro definition.
     assert!(
@@ -281,36 +299,38 @@ pub fn read_deprecated_lints() -> DeprecatedLints {
     );
 
     if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) {
+        let mut version = "";
         let mut name = "";
         let mut reason = "";
-        while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) {
-            res.deprecated.push(DeprecatedLint {
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut name, &mut reason]) {
+            deprecated.push(DeprecatedLint {
                 name: parse_str_single_line(path.as_ref(), name),
                 reason: parse_str_single_line(path.as_ref(), reason),
+                version: parse_str_single_line(path.as_ref(), version),
             });
         }
     } else {
         panic!("error reading deprecated lints");
     }
-    // position of the closing `]}` of `declare_with_version`
-    res.deprecated_end = searcher.pos();
 
     if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) {
+        let mut version = "";
         let mut old_name = "";
         let mut new_name = "";
-        while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) {
-            res.renamed.push(RenamedLint {
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut old_name, &mut new_name]) {
+            renamed.push(RenamedLint {
                 old_name: parse_str_single_line(path.as_ref(), old_name),
                 new_name: parse_str_single_line(path.as_ref(), new_name),
+                version: parse_str_single_line(path.as_ref(), version),
             });
         }
     } else {
         panic!("error reading renamed lints");
     }
-    // position of the closing `]}` of `declare_with_version`
-    res.renamed_end = searcher.pos();
 
-    res
+    deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
+    renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name));
+    (deprecated, renamed)
 }
 
 /// Removes the line splices and surrounding quotes from a string literal
@@ -366,7 +386,7 @@ mod tests {
             }
         "#;
         let mut result = Vec::new();
-        parse_clippy_lint_decls(CONTENTS, "module_name", &mut result);
+        parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result);
         for r in &mut result {
             r.declaration_range = Range::default();
         }
@@ -376,12 +396,14 @@ mod tests {
                 name: "ptr_arg".into(),
                 group: "style".into(),
                 module: "module_name".into(),
+                path: PathBuf::new(),
                 declaration_range: Range::default(),
             },
             Lint {
                 name: "doc_markdown".into(),
                 group: "pedantic".into(),
                 module: "module_name".into(),
+                path: PathBuf::new(),
                 declaration_range: Range::default(),
             },
         ];
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index ae2eabc45dd..255e36afe69 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -1,13 +1,14 @@
-use aho_corasick::{AhoCorasick, AhoCorasickBuilder};
 use core::fmt::{self, Display};
+use core::ops::Range;
 use core::slice;
 use core::str::FromStr;
 use rustc_lexer::{self as lexer, FrontmatterAllowed};
 use std::env;
+use std::ffi::OsStr;
 use std::fs::{self, OpenOptions};
 use std::io::{self, Read as _, Seek as _, SeekFrom, Write};
 use std::path::{Path, PathBuf};
-use std::process::{self, ExitStatus};
+use std::process::{self, Command, ExitStatus, Stdio};
 
 #[cfg(not(windows))]
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
@@ -15,14 +16,16 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
 
 #[derive(Clone, Copy)]
-pub enum FileAction {
+pub enum ErrAction {
     Open,
     Read,
     Write,
     Create,
     Rename,
+    Delete,
+    Run,
 }
-impl FileAction {
+impl ErrAction {
     fn as_str(self) -> &'static str {
         match self {
             Self::Open => "opening",
@@ -30,13 +33,15 @@ impl FileAction {
             Self::Write => "writing",
             Self::Create => "creating",
             Self::Rename => "renaming",
+            Self::Delete => "deleting",
+            Self::Run => "running",
         }
     }
 }
 
 #[cold]
 #[track_caller]
-pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! {
+pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! {
     panic!("error {} `{}`: {}", action.as_str(), path.display(), *err)
 }
 
@@ -52,7 +57,7 @@ impl<'a> File<'a> {
         let path = path.as_ref();
         match options.open(path) {
             Ok(inner) => Self { inner, path },
-            Err(e) => panic_file(&e, FileAction::Open, path),
+            Err(e) => panic_action(&e, ErrAction::Open, path),
         }
     }
 
@@ -63,7 +68,7 @@ impl<'a> File<'a> {
         match options.open(path) {
             Ok(inner) => Some(Self { inner, path }),
             Err(e) if e.kind() == io::ErrorKind::NotFound => None,
-            Err(e) => panic_file(&e, FileAction::Open, path),
+            Err(e) => panic_action(&e, ErrAction::Open, path),
         }
     }
 
@@ -81,7 +86,7 @@ impl<'a> File<'a> {
     pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String {
         match self.inner.read_to_string(dst) {
             Ok(_) => {},
-            Err(e) => panic_file(&e, FileAction::Read, self.path),
+            Err(e) => panic_action(&e, ErrAction::Read, self.path),
         }
         dst
     }
@@ -103,7 +108,7 @@ impl<'a> File<'a> {
             Err(e) => Err(e),
         };
         if let Err(e) = res {
-            panic_file(&e, FileAction::Write, self.path);
+            panic_action(&e, ErrAction::Write, self.path);
         }
     }
 }
@@ -165,9 +170,83 @@ impl Version {
     }
 }
 
+enum TomlPart<'a> {
+    Table(&'a str),
+    Value(&'a str, &'a str),
+}
+
+fn toml_iter(s: &str) -> impl Iterator<Item = (usize, TomlPart<'_>)> {
+    let mut pos = 0;
+    s.split('\n')
+        .map(move |s| {
+            let x = pos;
+            pos += s.len() + 1;
+            (x, s)
+        })
+        .filter_map(|(pos, s)| {
+            if let Some(s) = s.strip_prefix('[') {
+                s.split_once(']').map(|(name, _)| (pos, TomlPart::Table(name)))
+            } else if matches!(s.bytes().next(), Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')) {
+                s.split_once('=').map(|(key, value)| (pos, TomlPart::Value(key, value)))
+            } else {
+                None
+            }
+        })
+}
+
+pub struct CargoPackage<'a> {
+    pub name: &'a str,
+    pub version_range: Range<usize>,
+    pub not_a_platform_range: Range<usize>,
+}
+
+#[must_use]
+pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> {
+    let mut in_package = false;
+    let mut in_platform_deps = false;
+    let mut name = "";
+    let mut version_range = 0..0;
+    let mut not_a_platform_range = 0..0;
+    for (offset, part) in toml_iter(s) {
+        match part {
+            TomlPart::Table(name) => {
+                if in_platform_deps {
+                    not_a_platform_range.end = offset;
+                }
+                in_package = false;
+                in_platform_deps = false;
+
+                match name.trim() {
+                    "package" => in_package = true,
+                    "target.'cfg(NOT_A_PLATFORM)'.dependencies" => {
+                        in_platform_deps = true;
+                        not_a_platform_range.start = offset;
+                    },
+                    _ => {},
+                }
+            },
+            TomlPart::Value(key, value) if in_package => match key.trim_end() {
+                "name" => name = value.trim(),
+                "version" => {
+                    version_range.start = offset + (value.len() - value.trim().len()) + key.len() + 1;
+                    version_range.end = offset + key.len() + value.trim_end().len() + 1;
+                },
+                _ => {},
+            },
+            TomlPart::Value(..) => {},
+        }
+    }
+    CargoPackage {
+        name,
+        version_range,
+        not_a_platform_range,
+    }
+}
+
 pub struct ClippyInfo {
     pub path: PathBuf,
     pub version: Version,
+    pub has_intellij_hook: bool,
 }
 impl ClippyInfo {
     #[must_use]
@@ -177,35 +256,21 @@ impl ClippyInfo {
         loop {
             path.push("Cargo.toml");
             if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) {
-                let mut in_package = false;
-                let mut is_clippy = false;
-                let mut version: Option<Version> = None;
-
-                // Ad-hoc parsing to avoid dependencies. We control all the file so this
-                // isn't actually a problem
-                for line in file.read_to_cleared_string(&mut buf).lines() {
-                    if line.starts_with('[') {
-                        in_package = line.starts_with("[package]");
-                    } else if in_package && let Some((name, value)) = line.split_once('=') {
-                        match name.trim() {
-                            "name" => is_clippy = value.trim() == "\"clippy\"",
-                            "version"
-                                if let Some(value) = value.trim().strip_prefix('"')
-                                    && let Some(value) = value.strip_suffix('"') =>
-                            {
-                                version = value.parse().ok();
-                            },
-                            _ => {},
-                        }
+                file.read_to_cleared_string(&mut buf);
+                let package = parse_cargo_package(&buf);
+                if package.name == "\"clippy\"" {
+                    if let Some(version) = buf[package.version_range].strip_prefix('"')
+                        && let Some(version) = version.strip_suffix('"')
+                        && let Ok(version) = version.parse()
+                    {
+                        path.pop();
+                        return ClippyInfo {
+                            path,
+                            version,
+                            has_intellij_hook: !package.not_a_platform_range.is_empty(),
+                        };
                     }
-                }
-
-                if is_clippy {
-                    let Some(version) = version else {
-                        panic!("error reading clippy version from {}", file.path.display());
-                    };
-                    path.pop();
-                    return ClippyInfo { path, version };
+                    panic!("error reading clippy version from `{}`", file.path.display());
                 }
             }
 
@@ -258,6 +323,11 @@ impl UpdateMode {
     pub fn from_check(check: bool) -> Self {
         if check { Self::Check } else { Self::Change }
     }
+
+    #[must_use]
+    pub fn is_check(self) -> bool {
+        matches!(self, Self::Check)
+    }
 }
 
 #[derive(Default)]
@@ -366,53 +436,11 @@ pub fn update_text_region_fn(
     move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert)
 }
 
-#[must_use]
-pub fn is_ident_char(c: u8) -> bool {
-    matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
-}
-
-pub struct StringReplacer<'a> {
-    searcher: AhoCorasick,
-    replacements: &'a [(&'a str, &'a str)],
-}
-impl<'a> StringReplacer<'a> {
-    #[must_use]
-    pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self {
-        Self {
-            searcher: AhoCorasickBuilder::new()
-                .match_kind(aho_corasick::MatchKind::LeftmostLongest)
-                .build(replacements.iter().map(|&(x, _)| x))
-                .unwrap(),
-            replacements,
-        }
-    }
-
-    /// Replace substrings if they aren't bordered by identifier characters.
-    pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus {
-        move |_, src, dst| {
-            let mut pos = 0;
-            let mut changed = false;
-            for m in self.searcher.find_iter(src) {
-                if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
-                    && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0))
-                {
-                    changed = true;
-                    dst.push_str(&src[pos..m.start()]);
-                    dst.push_str(self.replacements[m.pattern()].1);
-                    pos = m.end();
-                }
-            }
-            dst.push_str(&src[pos..]);
-            UpdateStatus::from_changed(changed)
-        }
-    }
-}
-
 #[derive(Clone, Copy)]
-pub enum Token {
-    /// Matches any number of doc comments.
-    AnyDoc,
-    Ident(&'static str),
+pub enum Token<'a> {
+    /// Matches any number of comments / doc comments.
+    AnyComment,
+    Ident(&'a str),
     CaptureIdent,
     LitStr,
     CaptureLitStr,
@@ -431,29 +459,26 @@ pub enum Token {
     OpenBracket,
     OpenParen,
     Pound,
+    Semi,
+    Slash,
 }
 
 pub struct RustSearcher<'txt> {
     text: &'txt str,
     cursor: lexer::Cursor<'txt>,
     pos: u32,
-
-    // Either the next token or a zero-sized whitespace sentinel.
     next_token: lexer::Token,
 }
 impl<'txt> RustSearcher<'txt> {
     #[must_use]
+    #[expect(clippy::inconsistent_struct_constructor)]
     pub fn new(text: &'txt str) -> Self {
+        let mut cursor = lexer::Cursor::new(text, FrontmatterAllowed::Yes);
         Self {
             text,
-            cursor: lexer::Cursor::new(text, FrontmatterAllowed::Yes),
             pos: 0,
-
-            // Sentinel value indicating there is no read token.
-            next_token: lexer::Token {
-                len: 0,
-                kind: lexer::TokenKind::Whitespace,
-            },
+            next_token: cursor.advance_token(),
+            cursor,
         }
     }
 
@@ -463,6 +488,11 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
+    pub fn peek_len(&self) -> u32 {
+        self.next_token.len
+    }
+
+    #[must_use]
     pub fn peek(&self) -> lexer::TokenKind {
         self.next_token.kind
     }
@@ -485,37 +515,15 @@ impl<'txt> RustSearcher<'txt> {
 
     /// Consumes the next token if it matches the requested value and captures the value if
     /// requested. Returns true if a token was matched.
-    fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool {
+    fn read_token(&mut self, token: Token<'_>, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool {
         loop {
             match (token, self.next_token.kind) {
-                // Has to be the first match arm so the empty sentinel token will be handled.
-                // This will also skip all whitespace/comments preceding any tokens.
-                (
-                    _,
-                    lexer::TokenKind::Whitespace
-                    | lexer::TokenKind::LineComment { doc_style: None }
-                    | lexer::TokenKind::BlockComment {
-                        doc_style: None,
-                        terminated: true,
-                    },
-                ) => {
-                    self.step();
-                    if self.at_end() {
-                        // `AnyDoc` always matches.
-                        return matches!(token, Token::AnyDoc);
-                    }
-                },
-                (
-                    Token::AnyDoc,
+                (_, lexer::TokenKind::Whitespace)
+                | (
+                    Token::AnyComment,
                     lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. },
-                ) => {
-                    self.step();
-                    if self.at_end() {
-                        // `AnyDoc` always matches.
-                        return true;
-                    }
-                },
-                (Token::AnyDoc, _) => return true,
+                ) => self.step(),
+                (Token::AnyComment, _) => return true,
                 (Token::Bang, lexer::TokenKind::Bang)
                 | (Token::CloseBrace, lexer::TokenKind::CloseBrace)
                 | (Token::CloseBracket, lexer::TokenKind::CloseBracket)
@@ -529,6 +537,8 @@ impl<'txt> RustSearcher<'txt> {
                 | (Token::OpenBracket, lexer::TokenKind::OpenBracket)
                 | (Token::OpenParen, lexer::TokenKind::OpenParen)
                 | (Token::Pound, lexer::TokenKind::Pound)
+                | (Token::Semi, lexer::TokenKind::Semi)
+                | (Token::Slash, lexer::TokenKind::Slash)
                 | (
                     Token::LitStr,
                     lexer::TokenKind::Literal {
@@ -569,7 +579,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn find_token(&mut self, token: Token) -> bool {
+    pub fn find_token(&mut self, token: Token<'_>) -> bool {
         let mut capture = [].iter_mut();
         while !self.read_token(token, &mut capture) {
             self.step();
@@ -581,7 +591,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> {
+    pub fn find_capture_token(&mut self, token: Token<'_>) -> Option<&'txt str> {
         let mut res = "";
         let mut capture = &mut res;
         let mut capture = slice::from_mut(&mut capture).iter_mut();
@@ -595,7 +605,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool {
+    pub fn match_tokens(&mut self, tokens: &[Token<'_>], captures: &mut [&mut &'txt str]) -> bool {
         let mut captures = captures.iter_mut();
         tokens.iter().all(|&t| self.read_token(t, &mut captures))
     }
@@ -606,21 +616,107 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
     match OpenOptions::new().create_new(true).write(true).open(new_name) {
         Ok(file) => drop(file),
         Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
-        Err(e) => panic_file(&e, FileAction::Create, new_name),
+        Err(ref e) => panic_action(e, ErrAction::Create, new_name),
     }
     match fs::rename(old_name, new_name) {
         Ok(()) => true,
-        Err(e) => {
+        Err(ref e) => {
             drop(fs::remove_file(new_name));
-            if e.kind() == io::ErrorKind::NotFound {
+            // `NotADirectory` happens on posix when renaming a directory to an existing file.
+            // Windows will ignore this and rename anyways.
+            if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) {
                 false
             } else {
-                panic_file(&e, FileAction::Rename, old_name);
+                panic_action(e, ErrAction::Rename, old_name);
+            }
+        },
+    }
+}
+
+#[expect(clippy::must_use_candidate)]
+pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool {
+    match fs::create_dir(new_name) {
+        Ok(()) => {},
+        Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
+        Err(ref e) => panic_action(e, ErrAction::Create, new_name),
+    }
+    // Windows can't reliably rename to an empty directory.
+    #[cfg(windows)]
+    drop(fs::remove_dir(new_name));
+    match fs::rename(old_name, new_name) {
+        Ok(()) => true,
+        Err(ref e) => {
+            // Already dropped earlier on windows.
+            #[cfg(not(windows))]
+            drop(fs::remove_dir(new_name));
+            // `NotADirectory` happens on posix when renaming a file to an existing directory.
+            if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) {
+                false
+            } else {
+                panic_action(e, ErrAction::Rename, old_name);
             }
         },
     }
 }
 
 pub fn write_file(path: &Path, contents: &str) {
-    fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path));
+    fs::write(path, contents).unwrap_or_else(|e| panic_action(&e, ErrAction::Write, path));
+}
+
+#[must_use]
+pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> {
+    fn f(path: &Path, cmd: &mut Command) -> Vec<u8> {
+        match cmd
+            .stdin(Stdio::null())
+            .stdout(Stdio::piped())
+            .stderr(Stdio::inherit())
+            .output()
+        {
+            Ok(x) => match x.status.exit_ok() {
+                Ok(()) => x.stdout,
+                Err(ref e) => panic_action(e, ErrAction::Run, path),
+            },
+            Err(ref e) => panic_action(e, ErrAction::Run, path),
+        }
+    }
+    f(path.as_ref(), cmd)
+}
+
+pub fn run_with_args_split(
+    mut make_cmd: impl FnMut() -> Command,
+    mut run_cmd: impl FnMut(&mut Command),
+    args: impl Iterator<Item: AsRef<OsStr>>,
+) {
+    let mut cmd = make_cmd();
+    let mut len = 0;
+    for arg in args {
+        len += arg.as_ref().len();
+        cmd.arg(arg);
+        // Very conservative limit
+        if len > 10000 {
+            run_cmd(&mut cmd);
+            cmd = make_cmd();
+            len = 0;
+        }
+    }
+    if len != 0 {
+        run_cmd(&mut cmd);
+    }
+}
+
+#[expect(clippy::must_use_candidate)]
+pub fn delete_file_if_exists(path: &Path) -> bool {
+    match fs::remove_file(path) {
+        Ok(()) => true,
+        Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::IsADirectory) => false,
+        Err(ref e) => panic_action(e, ErrAction::Delete, path),
+    }
+}
+
+pub fn delete_dir_if_exists(path: &Path) {
+    match fs::remove_dir_all(path) {
+        Ok(()) => {},
+        Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) => {},
+        Err(ref e) => panic_action(e, ErrAction::Delete, path),
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 7e3cb404247..39e4e2e365e 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_lints"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 9ae746c13b2..852e48cbcae 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
-use rustc_attr_parsing::RustcVersion;
+use rustc_attr_data_structures::RustcVersion;
 use rustc_hir::{HirId, Lit};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 272444475c0..5c1c85d3918 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -6,9 +6,10 @@ use clippy_config::types::{
 };
 use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::is_cfg_test;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_hir::{
-    AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant,
-    VariantData,
+    AssocItemKind, Attribute, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind,
+    Variant, VariantData,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
@@ -28,6 +29,11 @@ declare_clippy_lint! {
     /// implemented in the code. Sometimes this will be referred to as
     /// "bikeshedding".
     ///
+    /// The content of items with a representation clause attribute, such as
+    /// `#[repr(C)]` will not be checked, as the order of their fields or
+    /// variants might be dictated by an external API (application binary
+    /// interface).
+    ///
     /// ### Default Ordering and Configuration
     ///
     /// As there is no generally applicable rule, and each project may have
@@ -256,6 +262,15 @@ impl ArbitrarySourceItemOrdering {
 
 impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if cx
+            .tcx
+            .hir_attrs(item.hir_id())
+            .iter()
+            .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..))))
+        {
+            // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API.
+            return;
+        }
         match &item.kind {
             ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => {
                 let mut cur_v: Option<&Variant<'_>> = None;
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index c073dee855e..6f2a6a36a38 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -3,14 +3,13 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{is_expr_final_block_expr, path_res};
+use clippy_utils::{is_expr_final_block_expr, path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -68,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                     return;
                 }
             }
-            let (message, replacement) = match method_segment.ident.as_str() {
-                "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
+            let (message, replacement) = match method_segment.ident.name {
+                sym::is_ok if type_suitable_to_unwrap(cx, args.type_at(1)) => {
                     ("called `assert!` with `Result::is_ok`", "unwrap")
                 },
-                "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
+                sym::is_err if type_suitable_to_unwrap(cx, args.type_at(0)) => {
                     ("called `assert!` with `Result::is_err`", "unwrap_err")
                 },
                 _ => return,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
index df01c7fde18..05d8a8c26d1 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
@@ -1,4 +1,4 @@
-use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr};
+use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
 use rustc_hir::Attribute;
 use rustc_lint::LateContext;
 use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index bc6ba84772b..7c6fd91ca67 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -6,7 +6,7 @@ use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use rustc_ast::ast::LitKind;
-use rustc_attr_parsing::RustcVersion;
+use rustc_attr_data_structures::RustcVersion;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index e92879b853d..4120e5c8cb7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             if signed {
                 return nbits;
             }
-            let max_bits = if method.ident.as_str() == "min" {
+            let max_bits = if method.ident.name == sym::min {
                 get_constant_bits(cx, right)
             } else {
                 None
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
         },
         ExprKind::MethodCall(method, _, [lo, hi], _) => {
-            if method.ident.as_str() == "clamp"
+            if method.ident.name == sym::clamp
                 //FIXME: make this a diagnostic item
                 && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi))
             {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index c8abf9dac9a..9a1ad8a7473 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -4,10 +4,11 @@ use std::ops::ControlFlow;
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{method_chain_args, sext};
+use clippy_utils::{method_chain_args, sext, sym};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::Symbol;
 
 use super::CAST_SIGN_LOSS;
 
@@ -16,24 +17,24 @@ use super::CAST_SIGN_LOSS;
 ///
 /// Methods that can overflow and return a negative value must not be included in this list,
 /// because casting their return values can still result in sign loss.
-const METHODS_RET_POSITIVE: &[&str] = &[
-    "checked_abs",
-    "saturating_abs",
-    "isqrt",
-    "checked_isqrt",
-    "rem_euclid",
-    "checked_rem_euclid",
-    "wrapping_rem_euclid",
+const METHODS_RET_POSITIVE: &[Symbol] = &[
+    sym::checked_abs,
+    sym::saturating_abs,
+    sym::isqrt,
+    sym::checked_isqrt,
+    sym::rem_euclid,
+    sym::checked_rem_euclid,
+    sym::wrapping_rem_euclid,
 ];
 
 /// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details.
 ///
 /// Methods that can overflow and return a negative value must not be included in this list,
 /// because casting their return values can still result in sign loss.
-const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"];
+const METHODS_POW: &[Symbol] = &[sym::pow, sym::saturating_pow, sym::checked_pow];
 
 /// A list of methods that act like `unwrap()`, and don't change the sign of the inner value.
-const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"];
+const METHODS_UNWRAP: &[Symbol] = &[sym::unwrap, sym::unwrap_unchecked, sym::expect, sym::into_ok];
 
 pub(super) fn check<'cx>(
     cx: &LateContext<'cx>,
@@ -129,7 +130,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
 
     // Calling on methods that always return non-negative values.
     if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind {
-        let mut method_name = path.ident.name.as_str();
+        let mut method_name = path.ident.name;
 
         // Peel unwrap(), expect(), etc.
         while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
@@ -138,7 +139,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
         {
             // The original type has changed, but we can't use `ty` here anyway, because it has been
             // moved.
-            method_name = inner_path.ident.name.as_str();
+            method_name = inner_path.ident.name;
             expr = recv;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
index 31cdd078f45..769cc120c95 100644
--- a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArg, Ty};
+use rustc_span::Symbol;
 use rustc_span::def_id::DefId;
-use rustc_span::{Symbol, sym};
 
 use super::CONFUSING_METHOD_TO_NUMERIC_CAST;
 
@@ -25,7 +26,6 @@ fn get_const_name_and_ty_name(
     method_def_id: DefId,
     generics: &[GenericArg<'_>],
 ) -> Option<(&'static str, &'static str)> {
-    let method_name = method_name.as_str();
     let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id);
 
     let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) {
@@ -39,14 +39,21 @@ fn get_const_name_and_ty_name(
         }
     } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id)
         && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity())
-        && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name)
+        && matches!(
+            method_name,
+            sym::min | sym::max | sym::minimum | sym::maximum | sym::min_value | sym::max_value
+        )
     {
         ty_name
     } else {
         return None;
     };
 
-    let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" };
+    let const_name = if matches!(method_name, sym::max | sym::maximum | sym::max_value) {
+        "MAX"
+    } else {
+        "MIN"
+    };
     Some((const_name, ty_name))
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index 2471c735551..c0c0a47f855 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::std_or_core;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{std_or_core, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_span::sym;
 
 use super::PTR_CAST_CONSTNESS;
 
@@ -78,9 +77,9 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>)
         && let ExprKind::Call(func, []) = cast_expr.kind
         && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
         && let Some(defid) = path.res.opt_def_id()
-        && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) {
-            (Some(sym::ptr_null), "cast_mut") => "null_mut",
-            (Some(sym::ptr_null_mut), "cast_const") => "null",
+        && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) {
+            (Some(sym::ptr_null), sym::cast_mut) => "null_mut",
+            (Some(sym::ptr_null_mut), sym::cast_const) => "null",
             _ => return,
         }
         && let Some(prefix) = std_or_core(cx)
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 1d44c7e9c88..5c64216dd92 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -3,14 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn};
+use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym};
 use core::ops::ControlFlow;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
+use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -104,7 +104,7 @@ impl CognitiveComplexity {
                 FnKind::Closure => {
                     let header_span = body_span.with_hi(decl.output.span().lo());
                     #[expect(clippy::range_plus_one)]
-                    if let Some(range) = header_span.map_range(cx, |src, range| {
+                    if let Some(range) = header_span.map_range(cx, |_, src, range| {
                         let mut idxs = src.get(range.clone())?.match_indices('|');
                         Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
                     }) {
@@ -157,9 +157,9 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
     }
 
     fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity");
+        self.limit.push_attrs(cx.sess(), attrs, sym::cognitive_complexity);
     }
     fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity");
+        self.limit.pop_attrs(cx.sess(), attrs, sym::cognitive_complexity);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 9c3009a86cd..238ebd4a444 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -75,11 +75,15 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
         }
 
         // Check that there exists at least one explicit else condition
-        let (conds, _) = if_sequence(expr);
+        let (conds, blocks) = if_sequence(expr);
         if conds.len() < 2 {
             return;
         }
 
+        if blocks.len() < 3 {
+            return;
+        }
+
         for cond in conds.windows(2) {
             if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) =
                 (&cond[0].kind, &cond[1].kind)
@@ -125,6 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
         let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else {
             unreachable!();
         };
+
         let lhs = Sugg::hir(cx, lhs, "..").maybe_paren();
         let rhs = Sugg::hir(cx, rhs, "..").addr();
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 42fbe6438d4..2467fc95fd0 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::{InteriorMut, needs_ordered_drop};
 use clippy_utils::visitors::for_each_expr_without_closures;
@@ -258,7 +258,7 @@ fn lint_branches_sharing_code<'tcx>(
         let span = span.with_hi(last_block.span.hi());
         // Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
         let span = span
-            .map_range(cx, |src, range| {
+            .map_range(cx, |_, src, range| {
                 (range.start > 4 && src.get(range.start - 4..range.start)? == "    ")
                     .then_some(range.start - 4..range.end)
             })
@@ -567,7 +567,7 @@ fn method_caller_is_mutable<'tcx>(
 
 /// Implementation of `IFS_SAME_COND`.
 fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) {
-    for (i, j) in search_same(
+    for group in search_same(
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
@@ -584,14 +584,8 @@ fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mu
             }
         },
     ) {
-        span_lint_and_note(
-            cx,
-            IFS_SAME_COND,
-            j.span,
-            "this `if` has the same condition as a previous `if`",
-            Some(i.span),
-            "same as this",
-        );
+        let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect();
+        span_lint(cx, IFS_SAME_COND, spans, "these `if` branches have the same condition");
     }
 }
 
@@ -609,14 +603,13 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
         SpanlessEq::new(cx).eq_expr(lhs, rhs)
     };
 
-    for (i, j) in search_same(conds, |e| hash_expr(cx, e), eq) {
-        span_lint_and_note(
+    for group in search_same(conds, |e| hash_expr(cx, e), eq) {
+        let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect();
+        span_lint(
             cx,
             SAME_FUNCTIONS_IN_IF_CONDITION,
-            j.span,
-            "this `if` has the same function call as a previous `if`",
-            Some(i.span),
-            "same as this",
+            spans,
+            "these `if` branches have the same function call",
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index bb825c7655f..5fcb851dfeb 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -764,6 +764,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
     crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
     crate::use_self::USE_SELF_INFO,
+    crate::useless_concat::USELESS_CONCAT_INFO,
     crate::useless_conversion::USELESS_CONVERSION_INFO,
     crate::vec::USELESS_VEC_INFO,
     crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 7c64bf46e7b..615421f3a40 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr};
+use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 94651538669..5204f73ea0a 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -14,36 +14,36 @@ macro_rules! declare_with_version {
 
 #[rustfmt::skip]
 declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [
-    #[clippy::version = "pre 1.29.0"]
-    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
+    #[clippy::version = "1.30.0"]
+    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"),
+    #[clippy::version = "pre 1.29.0"]
+    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
+    #[clippy::version = "1.54.0"]
+    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"),
+    #[clippy::version = "1.47.0"]
+    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
+    #[clippy::version = "1.44.0"]
+    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
+    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
+    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
-    #[clippy::version = "1.30.0"]
-    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
+    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
+    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
     #[clippy::version = "1.39.0"]
     ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"),
-    #[clippy::version = "1.44.0"]
-    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
-    #[clippy::version = "1.47.0"]
-    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
-    #[clippy::version = "1.54.0"]
-    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "1.54.0"]
     ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"),
 ]}
 
 #[rustfmt::skip]
@@ -61,6 +61,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::box_vec", "clippy::box_collection"),
     #[clippy::version = ""]
+    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
+    #[clippy::version = ""]
+    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
+    #[clippy::version = ""]
+    ("clippy::cmp_nan", "invalid_nan_comparisons"),
+    #[clippy::version = ""]
     ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
     #[clippy::version = ""]
     ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
@@ -70,15 +76,35 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     ("clippy::disallowed_method", "clippy::disallowed_methods"),
     #[clippy::version = ""]
     ("clippy::disallowed_type", "clippy::disallowed_types"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::double_neg", "double_negations"),
+    #[clippy::version = ""]
+    ("clippy::drop_bounds", "drop_bounds"),
+    #[clippy::version = ""]
+    ("clippy::drop_copy", "dropping_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::drop_ref", "dropping_references"),
     #[clippy::version = ""]
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
-    #[clippy::version = "1.51.0"]
-    ("clippy::find_map", "clippy::manual_find_map"),
     #[clippy::version = "1.53.0"]
     ("clippy::filter_map", "clippy::manual_filter_map"),
+    #[clippy::version = "1.51.0"]
+    ("clippy::find_map", "clippy::manual_find_map"),
     #[clippy::version = ""]
     ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"),
     #[clippy::version = ""]
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::forget_copy", "forgetting_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::forget_ref", "forgetting_references"),
+    #[clippy::version = ""]
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"),
@@ -91,7 +117,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
     #[clippy::version = ""]
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    #[clippy::version = ""]
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    #[clippy::version = "CURRENT_RUSTC_VERSION"]
+    ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"),
+    #[clippy::version = ""]
+    ("clippy::invalid_ref", "invalid_value"),
+    #[clippy::version = ""]
+    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
+    #[clippy::version = ""]
+    ("clippy::let_underscore_drop", "let_underscore_drop"),
+    #[clippy::version = ""]
     ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
+    #[clippy::version = "1.80.0"]
+    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
+    #[clippy::version = "1.80.0"]
+    ("clippy::mismatched_target_os", "unexpected_cfgs"),
     #[clippy::version = ""]
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
     #[clippy::version = ""]
@@ -107,6 +151,10 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
     #[clippy::version = ""]
+    ("clippy::panic_params", "non_fmt_panics"),
+    #[clippy::version = ""]
+    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
+    #[clippy::version = ""]
     ("clippy::ref_in_deref", "clippy::needless_borrow"),
     #[clippy::version = ""]
     ("clippy::result_expect_used", "clippy::expect_used"),
@@ -115,67 +163,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::result_unwrap_used", "clippy::unwrap_used"),
     #[clippy::version = ""]
+    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
+    #[clippy::version = ""]
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     #[clippy::version = ""]
     ("clippy::stutter", "clippy::module_name_repetitions"),
     #[clippy::version = ""]
+    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
+    #[clippy::version = ""]
     ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
     #[clippy::version = ""]
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
-    #[clippy::version = ""]
-    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
-    #[clippy::version = ""]
-    ("clippy::zero_width_space", "clippy::invisible_characters"),
-    #[clippy::version = ""]
-    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
-    #[clippy::version = ""]
-    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
-    #[clippy::version = ""]
-    ("clippy::cmp_nan", "invalid_nan_comparisons"),
-    #[clippy::version = "CURRENT_RUSTC_VERSION"]
-    ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::double_neg", "double_negations"),
-    #[clippy::version = ""]
-    ("clippy::drop_bounds", "drop_bounds"),
-    #[clippy::version = ""]
-    ("clippy::drop_copy", "dropping_copy_types"),
-    #[clippy::version = ""]
-    ("clippy::drop_ref", "dropping_references"),
-    #[clippy::version = ""]
-    ("clippy::fn_null_check", "useless_ptr_null_checks"),
-    #[clippy::version = ""]
-    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::forget_copy", "forgetting_copy_types"),
-    #[clippy::version = ""]
-    ("clippy::forget_ref", "forgetting_references"),
-    #[clippy::version = ""]
-    ("clippy::into_iter_on_array", "array_into_iter"),
-    #[clippy::version = ""]
-    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
-    #[clippy::version = ""]
-    ("clippy::invalid_ref", "invalid_value"),
-    #[clippy::version = ""]
-    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
-    #[clippy::version = ""]
-    ("clippy::let_underscore_drop", "let_underscore_drop"),
-    #[clippy::version = "1.80.0"]
-    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
-    #[clippy::version = ""]
-    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
-    #[clippy::version = "1.80.0"]
-    ("clippy::mismatched_target_os", "unexpected_cfgs"),
-    #[clippy::version = ""]
-    ("clippy::panic_params", "non_fmt_panics"),
-    #[clippy::version = ""]
-    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
-    #[clippy::version = ""]
-    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_float_to_int", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_char", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_float", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"),
     #[clippy::version = ""]
     ("clippy::undropped_manually_drops", "undropped_manually_drops"),
     #[clippy::version = ""]
@@ -183,15 +189,9 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::unused_label", "unused_labels"),
     #[clippy::version = ""]
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
+    #[clippy::version = ""]
     ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
     #[clippy::version = ""]
-    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_int_to_float", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_int_to_char", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_float_to_int", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"),
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
 ]}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 5edb5c23570..a22a2ee66d2 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -22,6 +22,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -252,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
         }
 
         let typeck = cx.typeck_results();
-        let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
+        let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
             // The whole chain of reference operations has been seen
             if let Some((state, data)) = self.state.take() {
                 report(cx, expr, state, data, typeck);
             }
             return;
         };
+        self.skip_expr = skip_expr;
 
         match (self.state.take(), kind) {
             (None, kind) => {
@@ -671,42 +673,38 @@ fn try_parse_ref_op<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
-) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
-    let (is_ufcs, def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
+) -> Option<(RefOp, &'tcx Expr<'tcx>, Option<HirId>)> {
+    let (call_path_id, def_id, arg) = match expr.kind {
+        ExprKind::MethodCall(_, arg, [], _) => (None, typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
-            Expr {
-                kind: ExprKind::Path(path),
+            &Expr {
+                kind: ExprKind::Path(QPath::Resolved(None, path)),
                 hir_id,
                 ..
             },
             [arg],
-        ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+        ) => (Some(hir_id), path.res.opt_def_id()?, arg),
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_raw_ptr() => {
-            return Some((RefOp::Deref, sub_expr));
+            return Some((RefOp::Deref, sub_expr, None));
+        },
+        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => {
+            return Some((RefOp::AddrOf(mutability), sub_expr, None));
         },
-        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
         _ => return None,
     };
-    if tcx.is_diagnostic_item(sym::deref_method, def_id) {
-        Some((
-            RefOp::Method {
-                mutbl: Mutability::Not,
-                is_ufcs,
-            },
-            arg,
-        ))
-    } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
-        Some((
-            RefOp::Method {
-                mutbl: Mutability::Mut,
-                is_ufcs,
-            },
-            arg,
-        ))
-    } else {
-        None
-    }
+    let mutbl = match tcx.get_diagnostic_name(def_id) {
+        Some(sym::deref_method) => Mutability::Not,
+        Some(sym::deref_mut_method) => Mutability::Mut,
+        _ => return None,
+    };
+    Some((
+        RefOp::Method {
+            mutbl,
+            is_ufcs: call_path_id.is_some(),
+        },
+        arg,
+        call_path_id,
+    ))
 }
 
 // Checks if the adjustments contains a deref of `ManuallyDrop<_>`
@@ -944,7 +942,7 @@ fn report<'tcx>(
             mutbl,
         } => {
             let mut app = Applicability::MachineApplicable;
-            let (expr_str, _expr_is_macro_call) =
+            let (expr_str, expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
             let (_, ref_count) = peel_middle_ty_refs(ty);
@@ -968,20 +966,11 @@ fn report<'tcx>(
                 "&"
             };
 
-            // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
-            // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
-            /*
-            expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < ExprPrecedence::Prefix {
+            let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix {
                 Cow::Owned(format!("({expr_str})"))
             } else {
                 expr_str
             };
-            */
-
-            // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
-            if is_ufcs {
-                return;
-            }
 
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 039937e0207..9ee32fced8c 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -113,7 +113,8 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
         }
 
         // check for `unwrap` and `expect` for both `Option` and `Result`
-        if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"]))
+        if let Some(arglists) =
+            method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
             && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
             && matches!(
                 get_type_diagnostic_name(cx, receiver_ty),
diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
index 9637546b868..ebfc9972aef 100644
--- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::AttrStyle;
 use rustc_ast::token::CommentKind;
-use rustc_attr_parsing::AttributeKind;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_errors::Applicability;
 use rustc_hir::Attribute;
 use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
index dc6cbb42543..7f7224ecfc6 100644
--- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
@@ -1,4 +1,4 @@
-use rustc_attr_parsing::AttributeKind;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Attribute, Item, ItemKind};
 use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index a38d6df89f2..8c12364883c 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -93,6 +93,7 @@ impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VA
 impl LateLintPass<'_> for EmptyWithBrackets {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Struct(ident, var_data, _) = &item.kind
+            && !item.span.from_expansion()
             && has_brackets(var_data)
             && let span_after_ident = item.span.with_lo(ident.span.hi())
             && has_no_fields(cx, var_data, span_after_ident)
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index a5a4e05b3a6..085ee4448a4 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, path_def_id};
+use clippy_utils::{is_expn_of, path_def_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::{ExpnId, sym};
+use rustc_span::ExpnId;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,9 +72,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
             };
 
             // ordering is important here, since `writeln!` uses `write!` internally
-            let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
+            let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
                 Some("writeln")
-            } else if is_expn_of(write_call.span, "write").is_some() {
+            } else if is_expn_of(write_call.span, sym::write).is_some() {
                 Some("write")
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 6a217b6182c..c0b0fd88d9e 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
         // Only lint on inherent methods, not trait methods.
         if let ImplItemKind::Fn(.., body_id) = item.kind
             && !item.generics.params.is_empty()
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
             && !item.span.in_external_macro(cx.sess().source_map())
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index c868b782f43..68d0cd19c8a 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
             }
 
             // check for `unwrap`
-            if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
+            if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
                 let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 012ad8e1a22..c51267567d0 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
                         },
                     );
                 }
-            } else if digits > max as usize && float_str.len() < sym_str.len() {
+            } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) {
                 span_lint_and_then(
                     cx,
                     EXCESSIVE_PRECISION,
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index e653a57196d..3c7e83b0697 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -294,8 +294,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
         && let Some(parent) = get_parent_expr(cx, expr)
     {
         if let Some(grandparent) = get_parent_expr(cx, parent)
-            && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
-            && method_name.as_str() == "sqrt"
+            && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind
+            && method.name == sym::sqrt
             && detect_hypot(cx, receiver).is_some()
         {
             return;
@@ -375,24 +375,10 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
         }
 
         // check if expression of the form x.powi(2) + y.powi(2)
-        if let ExprKind::MethodCall(
-            PathSegment {
-                ident: lmethod_name, ..
-            },
-            largs_0,
-            [largs_1, ..],
-            _,
-        ) = &add_lhs.kind
-            && let ExprKind::MethodCall(
-                PathSegment {
-                    ident: rmethod_name, ..
-                },
-                rargs_0,
-                [rargs_1, ..],
-                _,
-            ) = &add_rhs.kind
-            && lmethod_name.as_str() == "powi"
-            && rmethod_name.as_str() == "powi"
+        if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind
+            && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind
+            && lmethod.name == sym::powi
+            && rmethod.name == sym::powi
             && let ecx = ConstEvalCtxt::new(cx)
             && let Some(lvalue) = ecx.eval(largs_1)
             && let Some(rvalue) = ecx.eval(rargs_1)
@@ -482,8 +468,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
     ) = &expr.kind
     {
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind
-            && method_name.as_str() == "sqrt"
+            && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind
+            && method.name == sym::sqrt
             && detect_hypot(cx, receiver).is_some()
         {
             return;
@@ -623,27 +609,13 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 }
 
 fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
-    if let ExprKind::MethodCall(
-        PathSegment {
-            ident: method_name_a, ..
-        },
-        _,
-        args_a,
-        _,
-    ) = expr_a.kind
-        && let ExprKind::MethodCall(
-            PathSegment {
-                ident: method_name_b, ..
-            },
-            _,
-            args_b,
-            _,
-        ) = expr_b.kind
+    if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind
+        && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind
     {
-        return method_name_a.as_str() == method_name_b.as_str()
+        return method_a.name == method_b.name
             && args_a.len() == args_b.len()
-            && (["ln", "log2", "log10"].contains(&method_name_a.as_str())
-                || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
+            && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10)
+                || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
     }
 
     false
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 8a3f8e1c587..a26e736c7ae 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -15,7 +15,7 @@ use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
     FormatPlaceholder, FormatTrait,
 };
-use rustc_attr_parsing::RustcVersion;
+use rustc_attr_data_structures::RustcVersion;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index c3e0d5e8b69..70655838b6a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
-        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
+        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 07a92a4ed70..00ce4cfcc52 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
         && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
-        && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+        && trait_ref_of_method(cx, item.owner_id).is_none()
     {
         if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 4c17834c3ad..cab7a9fb709 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     }
 
                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
-                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
+                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| {
                             Some(src.get(range.clone())?.find("impl")? + 4..range.end)
                         });
                         if let Some(range) = range {
@@ -165,11 +165,12 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                             continue;
                         }
                         let generics_suggestion_span = generics.span.substitute_dummy({
-                            let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
-                                let (pre, post) = src.get(range.clone())?.split_once("fn")?;
-                                let pos = post.find('(')? + pre.len() + 2;
-                                Some(pos..pos)
-                            });
+                            let range =
+                                (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| {
+                                    let (pre, post) = src.get(range.clone())?.split_once("fn")?;
+                                    let pos = post.find('(')? + pre.len() + 2;
+                                    Some(pos..pos)
+                                });
                             if let Some(range) = range {
                                 range.with_ctxt(item.span.ctxt())
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index e55edb1fcaa..5d0bd3e8ca3 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_in_test;
 use clippy_utils::msrvs::Msrv;
-use rustc_attr_parsing::{RustcVersion, StabilityLevel, StableSince};
+use rustc_attr_data_structures::{RustcVersion, StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Expr, ExprKind, HirId, QPath};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 989997d69f7..0b1cae30ca5 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_copy;
-use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
+use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local, sym};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -72,7 +72,7 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
 impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
-            && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
+            && (!expr.span.from_expansion() || is_expn_of(expr.span, sym::if_chain).is_some())
             && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
             && let found_slices = find_slice_values(cx, let_pat)
             && !found_slices.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
index 3a28553b55e..7a751514b64 100644
--- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -1,13 +1,13 @@
 use crate::methods::method_call;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::peel_blocks;
+use clippy_utils::{peel_blocks, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,7 +57,7 @@ fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
 
 impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else {
+        let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else {
             return;
         };
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -70,9 +70,9 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
         let mut write = None;
 
         while let Some((name, recv, args, _, span)) = method_call(receiver) {
-            if name == "append" {
+            if name == sym::append {
                 append = index_if_arg_is_boolean(args, span);
-            } else if name == "write" {
+            } else if name == sym::write {
                 write = index_if_arg_is_boolean(args, span);
             }
             receiver = recv;
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index c4e10837bf1..bf3eafe09b3 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -4,6 +4,7 @@ use clippy_utils::{higher, sym};
 use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -119,33 +120,33 @@ use self::Heuristic::{All, Always, Any, First};
 /// returns an infinite or possibly infinite iterator. The finiteness
 /// is an upper bound, e.g., some methods can return a possibly
 /// infinite iterator at worst, e.g., `take_while`.
-const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
-    ("zip", 1, All, Infinite),
-    ("chain", 1, Any, Infinite),
-    ("cycle", 0, Always, Infinite),
-    ("map", 1, First, Infinite),
-    ("by_ref", 0, First, Infinite),
-    ("cloned", 0, First, Infinite),
-    ("rev", 0, First, Infinite),
-    ("inspect", 0, First, Infinite),
-    ("enumerate", 0, First, Infinite),
-    ("peekable", 1, First, Infinite),
-    ("fuse", 0, First, Infinite),
-    ("skip", 1, First, Infinite),
-    ("skip_while", 0, First, Infinite),
-    ("filter", 1, First, Infinite),
-    ("filter_map", 1, First, Infinite),
-    ("flat_map", 1, First, Infinite),
-    ("unzip", 0, First, Infinite),
-    ("take_while", 1, First, MaybeInfinite),
-    ("scan", 2, First, MaybeInfinite),
+const HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [
+    (sym::zip, 1, All, Infinite),
+    (sym::chain, 1, Any, Infinite),
+    (sym::cycle, 0, Always, Infinite),
+    (sym::map, 1, First, Infinite),
+    (sym::by_ref, 0, First, Infinite),
+    (sym::cloned, 0, First, Infinite),
+    (sym::rev, 0, First, Infinite),
+    (sym::inspect, 0, First, Infinite),
+    (sym::enumerate, 0, First, Infinite),
+    (sym::peekable, 1, First, Infinite),
+    (sym::fuse, 0, First, Infinite),
+    (sym::skip, 1, First, Infinite),
+    (sym::skip_while, 0, First, Infinite),
+    (sym::filter, 1, First, Infinite),
+    (sym::filter_map, 1, First, Infinite),
+    (sym::flat_map, 1, First, Infinite),
+    (sym::unzip, 0, First, Infinite),
+    (sym::take_while, 1, First, MaybeInfinite),
+    (sym::scan, 2, First, MaybeInfinite),
 ];
 
 fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
         ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len, heuristic, cap) in &HEURISTICS {
-                if method.ident.name.as_str() == name && args.len() == len {
+                if method.ident.name == name && args.len() == len {
                     return (match heuristic {
                         Always => Infinite,
                         First => is_infinite(cx, receiver),
@@ -183,36 +184,36 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
 
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
-const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
-    ("find", 1),
-    ("rfind", 1),
-    ("position", 1),
-    ("rposition", 1),
-    ("any", 1),
-    ("all", 1),
+const POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [
+    (sym::find, 1),
+    (sym::rfind, 1),
+    (sym::position, 1),
+    (sym::rposition, 1),
+    (sym::any, 1),
+    (sym::all, 1),
 ];
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
-const COMPLETING_METHODS: [(&str, usize); 12] = [
-    ("count", 0),
-    ("fold", 2),
-    ("for_each", 1),
-    ("partition", 1),
-    ("max", 0),
-    ("max_by", 1),
-    ("max_by_key", 1),
-    ("min", 0),
-    ("min_by", 1),
-    ("min_by_key", 1),
-    ("sum", 0),
-    ("product", 0),
+const COMPLETING_METHODS: [(Symbol, usize); 12] = [
+    (sym::count, 0),
+    (sym::fold, 2),
+    (sym::for_each, 1),
+    (sym::partition, 1),
+    (sym::max, 0),
+    (sym::max_by, 1),
+    (sym::max_by_key, 1),
+    (sym::min, 0),
+    (sym::min_by, 1),
+    (sym::min_by_key, 1),
+    (sym::sum, 0),
+    (sym::product, 0),
 ];
 
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
         ExprKind::MethodCall(method, receiver, args, _) => {
-            let method_str = method.ident.name.as_str();
+            let method_str = method.ident.name;
             for &(name, len) in &COMPLETING_METHODS {
                 if method_str == name && args.len() == len {
                     return is_infinite(cx, receiver);
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 1d582fb0223..7f2e25367a6 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, impl_item.owner_id).is_none()
         {
             show_lint(cx, impl_item);
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 006145cc623..92eb3d7a7c5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -35,7 +35,7 @@ extern crate rustc_abi;
 extern crate rustc_arena;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
-extern crate rustc_attr_parsing;
+extern crate rustc_attr_data_structures;
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_errors;
@@ -393,6 +393,7 @@ mod unwrap;
 mod unwrap_in_result;
 mod upper_case_acronyms;
 mod use_self;
+mod useless_concat;
 mod useless_conversion;
 mod vec;
 mod vec_init_then_push;
@@ -866,7 +867,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
     store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf)));
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
-    store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
+    store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf)));
     store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
     store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
@@ -937,6 +938,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
     store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
     store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
+    store.register_late_pass(|_| Box::new(useless_concat::UselessConcat));
     store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
     store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
     store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 9a64226b1ed..8fe0c9d60f9 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none();
             check_fn_inner(
                 cx,
                 sig,
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index d8af44233d3..14ccb6fce22 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -2,12 +2,12 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id};
+use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Body, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 pub struct LinesFilterMapOk {
     msrv: Msrv,
@@ -74,17 +74,17 @@ impl LateLintPass<'_> for LinesFilterMapOk {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
             && is_trait_method(cx, expr, sym::Iterator)
-            && let fm_method_str = fm_method.ident.as_str()
-            && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten")
+            && let fm_method_name = fm_method.ident.name
+            && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
-            && should_lint(cx, fm_args, fm_method_str)
+            && should_lint(cx, fm_args, fm_method_name)
             && self.msrv.meets(cx, msrvs::MAP_WHILE)
         {
             span_lint_and_then(
                 cx,
                 LINES_FILTER_MAP_OK,
                 fm_span,
-                format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",),
+                format!("`{fm_method_name}()` will run forever if the iterator repeatedly produces an `Err`",),
                 |diag| {
                     diag.span_note(
                         fm_receiver.span,
@@ -101,9 +101,9 @@ impl LateLintPass<'_> for LinesFilterMapOk {
     }
 }
 
-fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool {
+fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) -> bool {
     match args {
-        [] => method_str == "flatten",
+        [] => method_name == sym::flatten,
         [fm_arg] => {
             match &fm_arg.kind {
                 // Detect `Result::ok`
@@ -120,7 +120,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
                         && path_to_local_id(receiver, param.pat.hir_id)
                         && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
                     {
-                        is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok"
+                        is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
                     } else {
                         false
                     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
index 8916454ada1..a702e60f1c2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
@@ -3,12 +3,12 @@ use std::ops::ControlFlow;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{eq_expr_value, higher, path_to_local_id};
+use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 use super::CHAR_INDICES_AS_BYTE_INDICES;
 
@@ -16,22 +16,22 @@ use super::CHAR_INDICES_AS_BYTE_INDICES;
 // Note: `String` also has methods that work with byte indices,
 // but they all take `&mut self` and aren't worth considering since the user couldn't have called
 // them while the chars iterator is live anyway.
-const BYTE_INDEX_METHODS: &[&str] = &[
-    "is_char_boundary",
-    "floor_char_boundary",
-    "ceil_char_boundary",
-    "get",
-    "index",
-    "index_mut",
-    "get_mut",
-    "get_unchecked",
-    "get_unchecked_mut",
-    "slice_unchecked",
-    "slice_mut_unchecked",
-    "split_at",
-    "split_at_mut",
-    "split_at_checked",
-    "split_at_mut_checked",
+const BYTE_INDEX_METHODS: &[Symbol] = &[
+    sym::ceil_char_boundary,
+    sym::floor_char_boundary,
+    sym::get,
+    sym::get_mut,
+    sym::get_unchecked,
+    sym::get_unchecked_mut,
+    sym::index,
+    sym::index_mut,
+    sym::is_char_boundary,
+    sym::slice_mut_unchecked,
+    sym::slice_unchecked,
+    sym::split_at,
+    sym::split_at_checked,
+    sym::split_at_mut,
+    sym::split_at_mut_checked,
 ];
 
 const CONTINUE: ControlFlow<!, ()> = ControlFlow::Continue(());
@@ -88,7 +88,7 @@ fn check_index_usage<'tcx>(
             // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements
             // `Index` directly and no deref to `str` would happen in that case).
             if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str()
-                && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str())
+                && BYTE_INDEX_METHODS.contains(&segment.ident.name)
                 && eq_expr_value(cx, chars_recv, recv) =>
         {
             "passing a character position to a method that expects a byte index"
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
index d5ddc33e928..4aa1c2e211d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
@@ -1,7 +1,7 @@
 use super::EXPLICIT_INTO_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -76,7 +76,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<
     };
 
     let mut applicability = Applicability::MachineApplicable;
-    let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
+    let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0;
     span_lint_and_sugg(
         cx,
         EXPLICIT_INTO_ITER_LOOP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index d0b26c91ffa..010652e1cb9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -1,7 +1,7 @@
 use super::EXPLICIT_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::sym;
 use clippy_utils::ty::{
     implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
@@ -36,7 +36,7 @@ pub(super) fn check(
     }
 
     let mut applicability = Applicability::MachineApplicable;
-    let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
+    let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0;
     span_lint_and_sugg(
         cx,
         EXPLICIT_ITER_LOOP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 56d2bef2305..01c36b8cb12 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -25,8 +25,8 @@ mod while_let_loop;
 mod while_let_on_iterator;
 
 use clippy_config::Conf;
-use clippy_utils::higher;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::{higher, sym};
 use rustc_ast::Label;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
@@ -909,15 +909,17 @@ impl Loops {
     }
 
     fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
-        if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
-            match method.ident.as_str() {
-                "iter" | "iter_mut" => {
+        if !arg.span.from_expansion()
+            && let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind
+        {
+            match method.ident.name {
+                sym::iter | sym::iter_mut => {
                     explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow);
                 },
-                "into_iter" => {
+                sym::into_iter => {
                     explicit_into_iter_loop::check(cx, self_arg, arg);
                 },
-                "next" => {
+                sym::next => {
                     iter_next_loop::check(cx, arg);
                 },
                 _ => {},
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
index b4cd988329d..4439a28763a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::ty_from_hir_ty;
-use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
+use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
@@ -103,7 +103,7 @@ fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio
     } else {
         return None;
     };
-    (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
+    (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
 }
 
 /// Return `greater` if `smaller == greater - 1`
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 2dad0fa4925..0c09a47c965 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -1,11 +1,13 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
@@ -36,20 +38,33 @@ declare_clippy_lint! {
     complexity,
     "manual slice size calculation"
 }
-declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
+impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
+
+pub struct ManualSliceSizeCalculation {
+    msrv: Msrv,
+}
+
+impl ManualSliceSizeCalculation {
+    pub fn new(conf: &Conf) -> Self {
+        Self { msrv: conf.msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Binary(ref op, left, right) = expr.kind
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
-            // Does not apply inside const because size_of_val is not cost in stable.
-            && !is_in_const_context(cx)
             && let Some((receiver, refs_count)) = simplify(cx, left, right)
+            && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL))
         {
             let ctxt = expr.span.ctxt();
             let mut app = Applicability::MachineApplicable;
-            let deref = "*".repeat(refs_count - 1);
+            let deref = if refs_count > 0 {
+                "*".repeat(refs_count - 1)
+            } else {
+                "&".into()
+            };
             let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0;
             let Some(sugg) = std_or_core(cx) else { return };
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index 7ca3b712066..73ee1c3c78a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym, symbol};
+use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -67,7 +67,7 @@ impl LateLintPass<'_> for ManualStringNew {
 fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
     if let ExprKind::Lit(lit) = expr_kind
         && let LitKind::Str(value, _) = lit.node
-        && value == symbol::kw::Empty
+        && value == sym::empty
     {
         return true;
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index b607f8117eb..af6a1b07a49 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -255,7 +255,7 @@ impl LateLintPass<'_> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
         if let hir::StmtKind::Semi(expr) = stmt.kind
             && !stmt.span.from_expansion()
-            && let Some(arglists) = method_chain_args(expr, &["map"])
+            && let Some(arglists) = method_chain_args(expr, &[sym::map])
         {
             lint_map_unit_fn(cx, stmt, expr, arglists[0]);
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index a21597ffb93..dbb29ee776b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::{SpanlessEq, SpanlessHash, fulfill_or_allowed, is_lint_allowed, path_to_local, search_same};
 use core::cmp::Ordering;
 use core::{iter, slice};
+use itertools::Itertools;
 use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -110,57 +111,68 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
             && check_same_body()
     };
 
-    let mut appl = Applicability::MaybeIncorrect;
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
-    for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
-        if matches!(arm2.pat.kind, PatKind::Wild) {
-            if !cx.tcx.features().non_exhaustive_omitted_patterns_lint()
-                || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
-            {
-                let arm_span = adjusted_arm_span(cx, arm1.span);
-                span_lint_hir_and_then(
-                    cx,
-                    MATCH_SAME_ARMS,
-                    arm1.hir_id,
-                    arm_span,
-                    "this match arm has an identical body to the `_` wildcard arm",
-                    |diag| {
-                        diag.span_suggestion(arm_span, "try removing the arm", "", appl)
-                            .help("or try changing either arm body")
-                            .span_note(arm2.span, "`_` wildcard arm here");
-                    },
-                );
-            }
-        } else {
-            let back_block = backwards_blocking_idxs[j];
-            let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) {
-                (arm1, arm2)
-            } else {
-                (arm2, arm1)
-            };
-
-            span_lint_hir_and_then(
-                cx,
-                MATCH_SAME_ARMS,
-                keep_arm.hir_id,
-                keep_arm.span,
-                "this match arm has an identical body to another arm",
-                |diag| {
-                    let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "<pat2>", &mut appl);
-                    let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "<pat1>", &mut appl);
+    for mut group in search_same(&indexed_arms, hash, eq) {
+        // Filter out (and fulfill) `#[allow]`ed and `#[expect]`ed arms
+        group.retain(|(_, arm)| !fulfill_or_allowed(cx, MATCH_SAME_ARMS, [arm.hir_id]));
 
-                    diag.multipart_suggestion(
-                        "or try merging the arm patterns and removing the obsolete arm",
-                        vec![
-                            (keep_arm.pat.span, format!("{keep_pat_snip} | {move_pat_snip}")),
-                            (adjusted_arm_span(cx, move_arm.span), String::new()),
-                        ],
-                        appl,
-                    )
-                    .help("try changing either arm body");
-                },
-            );
+        if group.len() < 2 {
+            continue;
         }
+
+        span_lint_and_then(
+            cx,
+            MATCH_SAME_ARMS,
+            group.iter().map(|(_, arm)| arm.span).collect_vec(),
+            "these match arms have identical bodies",
+            |diag| {
+                diag.help("if this is unintentional make the arms return different values");
+
+                if let [prev @ .., (_, last)] = group.as_slice()
+                    && is_wildcard_arm(last.pat)
+                    && is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, last.hir_id)
+                {
+                    diag.span_label(last.span, "the wildcard arm");
+
+                    let s = if prev.len() > 1 { "s" } else { "" };
+                    diag.multipart_suggestion_verbose(
+                        format!("otherwise remove the non-wildcard arm{s}"),
+                        prev.iter()
+                            .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new()))
+                            .collect(),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else if let &[&(first_idx, _), .., &(last_idx, _)] = group.as_slice() {
+                    let back_block = backwards_blocking_idxs[last_idx];
+                    let split = if back_block < first_idx
+                        || (back_block == 0 && forwards_blocking_idxs[first_idx] <= last_idx)
+                    {
+                        group.split_first()
+                    } else {
+                        group.split_last()
+                    };
+
+                    if let Some(((_, dest), src)) = split
+                        && let Some(pat_snippets) = group
+                            .iter()
+                            .map(|(_, arm)| arm.pat.span.get_source_text(cx))
+                            .collect::<Option<Vec<_>>>()
+                    {
+                        let mut suggs = src
+                            .iter()
+                            .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new()))
+                            .collect_vec();
+
+                        suggs.push((dest.pat.span, pat_snippets.iter().join(" | ")));
+                        diag.multipart_suggestion_verbose(
+                            "otherwise merge the patterns into a single arm",
+                            suggs,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            },
+        );
     }
 }
 
@@ -450,3 +462,11 @@ fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
     pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.swap_remove(&id));
     result && ids.is_empty()
 }
+
+fn is_wildcard_arm(pat: &Pat<'_>) -> bool {
+    match pat.kind {
+        PatKind::Wild => true,
+        PatKind::Or([.., last]) => matches!(last.kind, PatKind::Wild),
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index c6ebd6144c7..c128fc40b73 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -28,7 +28,7 @@ use clippy_config::Conf;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::{
-    higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments,
+    higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym,
 };
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -1053,13 +1053,13 @@ impl_lint_pass!(Matches => [
 impl<'tcx> LateLintPass<'tcx> for Matches {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
+        if is_direct_expn_of(expr.span, sym::matches).is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if is_direct_expn_of(expr.span, "matches").is_some()
+            if is_direct_expn_of(expr.span, sym::matches).is_some()
                 && let [arm, _] = arms
             {
                 redundant_pattern_match::check_match(cx, expr, ex, arms);
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 6c5d7cab203..b04db03f8d2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -74,7 +74,7 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>])
         }
 
         if let PatKind::Wild = arm.pat.kind {
-            if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+            if !eq_expr_value(cx, match_expr, arm_expr) {
                 return false;
             }
         } else if !pat_same_as_expr(arm.pat, arm_expr) {
@@ -103,27 +103,18 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool
             if matches!(else_expr.kind, ExprKind::Block(..)) {
                 return false;
             }
-            let ret = strip_return(else_expr);
             let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
             if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
-                return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
+                return is_res_lang_ctor(cx, path_res(cx, else_expr), OptionNone)
+                    || eq_expr_value(cx, if_let.let_expr, else_expr);
             }
-            return eq_expr_value(cx, if_let.let_expr, ret);
+            return eq_expr_value(cx, if_let.let_expr, else_expr);
         }
     }
 
     false
 }
 
-/// Strip `return` keyword if the expression type is `ExprKind::Ret`.
-fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
-    if let ExprKind::Ret(Some(ret)) = expr.kind {
-        ret
-    } else {
-        expr
-    }
-}
-
 /// Manually check for coercion casting by checking if the type of the match operand or let expr
 /// differs with the assigned local variable or the function return type.
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
@@ -161,7 +152,6 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
 }
 
 fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
-    let expr = strip_return(expr);
     match (&pat.kind, &expr.kind) {
         // Example: `Some(val) => Some(val)`
         (PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 9bbef8da0a4..7c6d45e4240 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -3,14 +3,14 @@ use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
-use clippy_utils::{is_in_const_context, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local, sym};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
@@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
         } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind
             && let Some(binding) = get_pat_binding(cx, recv, outer_arm)
         {
-            check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding);
+            check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding);
         }
     }
 }
@@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
 fn check_method_calls<'tcx>(
     cx: &LateContext<'tcx>,
     arm: &Arm<'tcx>,
-    method: &str,
+    method: Symbol,
     recv: &Expr<'_>,
     args: &[Expr<'_>],
     if_expr: &Expr<'_>,
@@ -112,7 +112,7 @@ fn check_method_calls<'tcx>(
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
     let slice_like = ty.is_slice() || ty.is_array();
 
-    let sugg = if method == "is_empty" {
+    let sugg = if method == sym::is_empty {
         // `s if s.is_empty()` becomes ""
         // `arr if arr.is_empty()` becomes []
 
@@ -137,9 +137,9 @@ fn check_method_calls<'tcx>(
 
         if needles.is_empty() {
             sugg.insert_str(1, "..");
-        } else if method == "starts_with" {
+        } else if method == sym::starts_with {
             sugg.insert_str(sugg.len() - 1, ", ..");
-        } else if method == "ends_with" {
+        } else if method == sym::ends_with {
             sugg.insert_str(1, ".., ");
         } else {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index db20be40f27..aa9be61bf4d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -273,7 +273,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
         if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
-            let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
+            let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index d7dc7604088..0f3ad40784d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -4,7 +4,7 @@ use crate::FxHashSet;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{first_line_of_span, indent_of, snippet};
 use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
-use clippy_utils::{get_attr, is_lint_allowed};
+use clippy_utils::{get_attr, is_lint_allowed, sym};
 use itertools::Itertools;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxIndexSet;
@@ -186,7 +186,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
             && get_attr(
                 self.cx.sess(),
                 self.cx.tcx.get_attrs_unchecked(adt.did()),
-                "has_significant_drop",
+                sym::has_significant_drop,
             )
             .count()
                 > 0
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index de22514c37c..02fc09170e5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
 
     if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
         && let Some((name, _, _, _, _)) = method_call(parent)
-        && name == "unwrap"
+        && name == sym::unwrap
     {
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index 4ae0aeea2d1..de27a45ba4d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -5,12 +5,13 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
+use rustc_span::Symbol;
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 pub(super) fn check(
     cx: &LateContext<'_>,
     info: &crate::methods::BinaryExprInfo<'_>,
-    chain_methods: &[&str],
+    chain_methods: &[Symbol],
     lint: &'static Lint,
     suggest: &str,
 ) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 9c45ec2e56c..1c72a973cfa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -5,12 +5,13 @@ use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, Lint};
+use rustc_span::Symbol;
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
 pub(super) fn check(
     cx: &LateContext<'_>,
     info: &crate::methods::BinaryExprInfo<'_>,
-    chain_methods: &[&str],
+    chain_methods: &[Symbol],
     lint: &'static Lint,
     suggest: &str,
 ) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
index 2efff4c3c54..8729e91d191 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
@@ -1,13 +1,14 @@
 use crate::methods::chars_cmp;
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_LAST_CMP;
 
 /// Checks for the `CHARS_LAST_CMP` lint.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
+    if chars_cmp::check(cx, info, &[sym::chars, sym::last], CHARS_LAST_CMP, "ends_with") {
         true
     } else {
-        chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
+        chars_cmp::check(cx, info, &[sym::chars, sym::next_back], CHARS_LAST_CMP, "ends_with")
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
index 5b8713f7d79..027d0a3947b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
@@ -1,13 +1,26 @@
 use crate::methods::chars_cmp_with_unwrap;
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_LAST_CMP;
 
 /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
+    if chars_cmp_with_unwrap::check(
+        cx,
+        info,
+        &[sym::chars, sym::last, sym::unwrap],
+        CHARS_LAST_CMP,
+        "ends_with",
+    ) {
         true
     } else {
-        chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
+        chars_cmp_with_unwrap::check(
+            cx,
+            info,
+            &[sym::chars, sym::next_back, sym::unwrap],
+            CHARS_LAST_CMP,
+            "ends_with",
+        )
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
index b631fecab97..2438843bf3a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
@@ -1,8 +1,9 @@
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_NEXT_CMP;
 
 /// Checks for the `CHARS_NEXT_CMP` lint.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
+    crate::methods::chars_cmp::check(cx, info, &[sym::chars, sym::next], CHARS_NEXT_CMP, "starts_with")
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
index caf21d3ff3b..9b3609f19d7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
@@ -1,8 +1,15 @@
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_NEXT_CMP;
 
 /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
+    crate::methods::chars_cmp_with_unwrap::check(
+        cx,
+        info,
+        &[sym::chars, sym::next, sym::unwrap],
+        CHARS_NEXT_CMP,
+        "starts_with",
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
index f7bf8764bde..6d0b944df55 100644
--- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{eq_expr_value, get_parent_expr};
+use clippy_utils::{eq_expr_value, get_parent_expr, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
         // If the parent node's `to` argument is the same as the `to` argument
         // of the last replace call in the current chain, don't lint as it was already linted
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent)
+            && let Some((sym::replace, _, [current_from, current_to], _, _)) = method_call(parent)
             && eq_expr_value(cx, to, current_to)
             && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
         {
@@ -47,7 +47,7 @@ fn collect_replace_calls<'tcx>(
     let mut from_args = VecDeque::new();
 
     let _: Option<()> = for_each_expr_without_closures(expr, |e| {
-        if let Some(("replace", _, [from, to], _, _)) = method_call(e) {
+        if let Some((sym::replace, _, [from, to], _, _)) = method_call(e) {
             if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
                 methods.push_front(e);
                 from_args.push_front(from);
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index f5688e370a4..82e5a6d5a41 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -6,8 +6,8 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::Span;
 use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 use super::EXPECT_FUN_CALL;
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
     format_args_storage: &FormatArgsStorage,
     expr: &hir::Expr<'_>,
     method_span: Span,
-    name: &str,
+    name: Symbol,
     receiver: &'tcx hir::Expr<'tcx>,
     args: &'tcx [hir::Expr<'tcx>],
 ) {
@@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
+    if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index 460ec7b3640..db60061904f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
 
 use super::EXTEND_WITH_DRAIN;
 
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     if is_type_diagnostic_item(cx, ty, sym::Vec)
         //check source object
         && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind
-        && src_method.ident.as_str() == "drain"
+        && src_method.ident.name == sym::drain
         && let src_ty = cx.typeck_results().expr_ty(drain_vec)
         //check if actual src type is mutable for code suggestion
         && let immutable = src_ty.is_mutable_ptr()
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 519091406cc..9724463f0c0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,15 +1,15 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs};
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 use super::IMPLICIT_CLONE;
 
-pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
@@ -43,12 +43,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
 /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
 /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
 /// `is_to_owned_like` in `unnecessary_to_owned.rs`.
-pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
+pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool {
     match method_name {
-        "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
-        "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
-        "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
-        "to_vec" => cx
+        sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr),
+        sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
+        sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
+        sym::to_vec => cx
             .tcx
             .impl_of_method(method_def_id)
             .filter(|&impl_did| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index 17cc07b91c5..b4ab313fe98 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -5,11 +5,16 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_CLONED_COLLECT;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    method_name: Symbol,
+    expr: &hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+) {
     let expr_ty = cx.typeck_results().expr_ty(expr);
     if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
         && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index 209cf2fcc0a..6b64cc8b50a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -5,11 +5,11 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_COUNT;
 
-pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) {
     let ty = cx.typeck_results().expr_ty(recv);
     let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
         "slice"
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 3ac9299ba91..c88462129af 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,12 +1,12 @@
 use super::ITER_KV_MAP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::pat_is_wild;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{pat_is_wild, sym};
 use rustc_hir::{Body, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 /// lint use of:
 ///
@@ -16,13 +16,13 @@ use rustc_span::sym;
 /// on `HashMaps` and `BTreeMaps` in std
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    map_type: &'tcx str,     // iter / into_iter
+    map_type: Symbol,        // iter / into_iter
     expr: &'tcx Expr<'tcx>,  // .iter().map(|(_, v_| v))
     recv: &'tcx Expr<'tcx>,  // hashmap
     m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
     msrv: Msrv,
 ) {
-    if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) {
+    if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) {
         return;
     }
     if !expr.span.from_expansion()
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
     {
         let mut applicability = rustc_errors::Applicability::MachineApplicable;
         let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
-        let into_prefix = if map_type == "into_iter" { "into_" } else { "" };
+        let into_prefix = if map_type == sym::into_iter { "into_" } else { "" };
 
         if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
             && let [local_ident] = path.segments
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 82bda5d9512..1fdbd81bf24 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sym;
 use clippy_utils::ty::get_type_diagnostic_name;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::Span;
-use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 
 use super::ITER_NTH;
 
@@ -12,7 +12,7 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
     iter_recv: &'tcx hir::Expr<'tcx>,
-    iter_method: &str,
+    iter_method: Symbol,
     iter_span: Span,
     nth_span: Span,
 ) -> bool {
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         expr.span,
         format!("called `.{iter_method}().nth()` on a {caller_type}"),
         |diag| {
-            let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" };
+            let get_method = if iter_method == sym::iter_mut { "get_mut" } else { "get" };
             diag.span_suggestion_verbose(
                 iter_span.to(nth_span),
                 format!("`{get_method}` is equivalent but more concise"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 9d562f5e51d..c0366765234 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -2,7 +2,7 @@ use std::iter::once;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
-use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core};
+use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym};
 
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirId;
 use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 
 use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
 
@@ -51,7 +52,7 @@ fn is_arg_ty_unified_in_fn<'tcx>(
         .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args)))
 }
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, recv: &'tcx Expr<'tcx>) {
     let item = match recv.kind {
         ExprKind::Array([]) => None,
         ExprKind::Array([e]) => Some(e),
@@ -60,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method
         _ => return,
     };
     let iter_type = match method_name {
-        "iter" => IterType::Iter,
-        "iter_mut" => IterType::IterMut,
-        "into_iter" => IterType::IntoIter,
+        sym::iter => IterType::Iter,
+        sym::iter_mut => IterType::IterMut,
+        sym::into_iter => IterType::IntoIter,
         _ => return,
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 7bb625222ec..f5fe4316eb0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -8,7 +8,7 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl
 use rustc_lint::LateContext;
 use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty::{self, BorrowKind};
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_OVEREAGER_CLONED;
 use crate::redundant_clone::REDUNDANT_CLONE;
@@ -26,7 +26,7 @@ pub(super) enum Op<'a> {
     // later `.cloned()`
     // and add `&` to the parameter of closure parameter
     // e.g. `find` `filter`
-    FixClosure(&'a str, &'a Expr<'a>),
+    FixClosure(Symbol, &'a Expr<'a>),
 
     // later `.cloned()`
     // e.g. `skip` `take`
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
index 3fa83cd39d1..a8445b68dd6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
@@ -168,7 +168,7 @@ fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option<String> {
 
 fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     match &e.kind {
-        ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver),
+        ExprKind::MethodCall(method, receiver, [], _) if method.ident.name == sym::cast => Some(receiver),
         ExprKind::Cast(expr, _) => Some(expr),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index 173ebcb7020..21f2ce8b7c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -3,18 +3,18 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::get_field_by_name;
 use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
-use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id};
+use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_span::{DUMMY_SP, Span, Symbol, sym};
+use rustc_span::{DUMMY_SP, Span, Symbol};
 
 use super::MANUAL_INSPECT;
 
 #[expect(clippy::too_many_lines)]
-pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) {
+pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: Symbol, name_span: Span, msrv: Msrv) {
     if let ExprKind::Closure(c) = arg.kind
         && matches!(c.kind, ClosureKind::Closure)
         && let typeck = cx.typeck_results()
@@ -101,7 +101,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
                 UseKind::Borrowed(s) => {
                     #[expect(clippy::range_plus_one)]
-                    let range = s.map_range(cx, |src, range| {
+                    let range = s.map_range(cx, |_, src, range| {
                         let src = src.get(range.clone())?;
                         let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
                         trimmed.starts_with('&').then(|| {
@@ -168,8 +168,8 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 edits.extend(addr_of_edits);
             }
             let edit = match name {
-                "map" => "inspect",
-                "map_err" => "inspect_err",
+                sym::map => "inspect",
+                sym::map_err => "inspect_err",
                 _ => return,
             };
             edits.push((name_span, edit.to_string()));
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 05360144657..98def66ca14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -5,7 +5,7 @@ use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Node, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use super::MAP_IDENTITY;
 
@@ -14,7 +14,7 @@ pub(super) fn check(
     expr: &hir::Expr<'_>,
     caller: &hir::Expr<'_>,
     map_arg: &hir::Expr<'_>,
-    name: &str,
+    name: Symbol,
     _map_span: Span,
 ) {
     let caller_ty = cx.typeck_results().expr_ty(caller);
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e0e6a1a59b6..d2d59f0013c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -150,7 +150,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
 use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::FxHashSet;
@@ -159,7 +159,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, kw};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -4711,17 +4711,15 @@ impl_lint_pass!(Methods => [
 /// Extracts a method call name, args, and `Span` of the method name.
 /// This ensures that neither the receiver nor any of the arguments
 /// come from expansion.
-pub fn method_call<'tcx>(
-    recv: &'tcx Expr<'tcx>,
-) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
+pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
     if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
         && !args.iter().any(|e| e.span.from_expansion())
         && !receiver.span.from_expansion()
     {
-        let name = path.ident.name.as_str();
-        return Some((name, receiver, args, path.ident.span, call_span));
+        Some((path.ident.name, receiver, args, path.ident.span, call_span))
+    } else {
+        None
     }
-    None
 }
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -4743,13 +4741,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             },
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
-                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args);
                 expect_fun_call::check(
                     cx,
                     &self.format_args,
                     expr,
                     method_span,
-                    method_call.ident.as_str(),
+                    method_call.ident.name,
                     receiver,
                     args,
                 );
@@ -4778,7 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
-        let name = impl_item.ident.name.as_str();
+        let name = impl_item.ident.name;
         let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir_expect_item(parent);
         let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
@@ -4851,7 +4849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 return;
             }
 
-            if name == "new" && ret_ty != self_ty {
+            if name == sym::new && ret_ty != self_ty {
                 span_lint(
                     cx,
                     NEW_RET_NO_SELF,
@@ -4881,7 +4879,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
             wrong_self_convention::check(
                 cx,
-                item.ident.name.as_str(),
+                item.ident.name,
                 self_ty,
                 first_arg_ty,
                 first_arg_hir_ty.span,
@@ -4912,14 +4910,17 @@ impl Methods {
         // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
             match (name, args) {
-                ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
+                (
+                    sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
+                    [_arg],
+                ) => {
                     zst_offset::check(cx, expr, recv);
                 },
-                ("all", [arg]) => {
+                (sym::all, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     needless_character_iteration::check(cx, expr, recv, arg, true);
                     match method_call(recv) {
-                        Some(("cloned", recv2, [], _, _)) => {
+                        Some((sym::cloned, recv2, [], _, _)) => {
                             iter_overeager_cloned::check(
                                 cx,
                                 expr,
@@ -4929,13 +4930,13 @@ impl Methods {
                                 false,
                             );
                         },
-                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                        Some((sym::map, _, [map_arg], _, map_call_span)) => {
                             map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all");
                         },
                         _ => {},
                     }
                 },
-                ("and_then", [arg]) => {
+                (sym::and_then, [arg]) => {
                     let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
                     let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
                     if !biom_option_linted && !biom_result_linted {
@@ -4945,11 +4946,11 @@ impl Methods {
                         }
                     }
                 },
-                ("any", [arg]) => {
+                (sym::any, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     needless_character_iteration::check(cx, expr, recv, arg, false);
                     match method_call(recv) {
-                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                        Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                             cx,
                             expr,
                             recv,
@@ -4957,80 +4958,79 @@ impl Methods {
                             iter_overeager_cloned::Op::NeedlessMove(arg),
                             false,
                         ),
-                        Some(("chars", recv, _, _, _))
+                        Some((sym::chars, recv, _, _, _))
                             if let ExprKind::Closure(arg) = arg.kind
                                 && let body = cx.tcx.hir_body(arg.body)
                                 && let [param] = body.params =>
                         {
                             string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv);
                         },
-                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                        Some((sym::map, _, [map_arg], _, map_call_span)) => {
                             map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any");
                         },
-                        Some(("iter", iter_recv, ..)) => {
+                        Some((sym::iter, iter_recv, ..)) => {
                             manual_contains::check(cx, expr, iter_recv, arg);
                         },
                         _ => {},
                     }
                 },
-                ("arg", [arg]) => {
+                (sym::arg, [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
                 },
-                ("as_deref" | "as_deref_mut", []) => {
+                (sym::as_deref | sym::as_deref_mut, []) => {
                     needless_option_as_deref::check(cx, expr, recv, name);
                 },
-                ("as_bytes", []) => {
-                    if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
+                (sym::as_bytes, []) => {
+                    if let Some((sym::as_str, recv, [], as_str_span, _)) = method_call(recv) {
                         redundant_as_str::check(cx, expr, recv, as_str_span, span);
                     }
                     sliced_string_as_bytes::check(cx, expr, recv);
                 },
-                ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
-                ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv),
-                ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
-                ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
-                ("bytes", []) => unbuffered_bytes::check(cx, expr, recv),
-                ("cloned", []) => {
+                (sym::as_mut | sym::as_ref, []) => useless_asref::check(cx, expr, name, recv),
+                (sym::as_ptr, []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv),
+                (sym::assume_init, []) => uninit_assumed_init::check(cx, expr, recv),
+                (sym::bytes, []) => unbuffered_bytes::check(cx, expr, recv),
+                (sym::cloned, []) => {
                     cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv);
                     option_as_ref_cloned::check(cx, recv, span);
                 },
-                ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
+                (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => {
                     needless_collect::check(cx, span, expr, recv, call_span);
                     match method_call(recv) {
-                        Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
+                        Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => {
                             iter_cloned_collect::check(cx, name, expr, recv2);
                         },
-                        Some(("map", m_recv, [m_arg], m_ident_span, _)) => {
+                        Some((sym::map, m_recv, [m_arg], m_ident_span, _)) => {
                             map_collect_result_unit::check(cx, expr, m_recv, m_arg);
                             format_collect::check(cx, expr, m_arg, m_ident_span);
                         },
-                        Some(("take", take_self_arg, [take_arg], _, _)) => {
+                        Some((sym::take, take_self_arg, [take_arg], _, _)) => {
                             if self.msrv.meets(cx, msrvs::STR_REPEAT) {
                                 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                             }
                         },
-                        Some(("drain", recv, args, ..)) => {
+                        Some((sym::drain, recv, args, ..)) => {
                             drain_collect::check(cx, args, expr, recv);
                         },
                         _ => {},
                     }
                 },
-                ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
-                    Some(("cloned", recv2, [], _, _)) => {
+                (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
+                    Some((sym::cloned, recv2, [], _, _)) => {
                         iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false);
                     },
-                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
+                    Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
-                    Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
-                    Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
-                    Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+                    Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
-                ("min" | "max", [arg]) => {
+                (sym::min | sym::max, [arg]) => {
                     unnecessary_min_or_max::check(cx, expr, name, recv, arg);
                 },
-                ("drain", ..) => {
+                (sym::drain, ..) => {
                     if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
                         && matches!(kind, StmtKind::Semi(_))
                         && args.len() <= 1
@@ -5040,31 +5040,31 @@ impl Methods {
                         iter_with_drain::check(cx, expr, recv, span, arg);
                     }
                 },
-                ("ends_with", [arg]) => {
+                (sym::ends_with, [arg]) => {
                     if let ExprKind::MethodCall(.., span) = expr.kind {
                         case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv);
                     }
                     path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles);
                 },
-                ("expect", [_]) => {
+                (sym::expect, [_]) => {
                     match method_call(recv) {
-                        Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
-                        Some(("err", recv, [], err_span, _)) => {
+                        Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv),
+                        Some((sym::err, recv, [], err_span, _)) => {
                             err_expect::check(cx, expr, recv, span, err_span, self.msrv);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
+                (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("extend", [arg]) => {
+                (sym::extend, [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
                 },
-                ("filter", [arg]) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::filter, [arg]) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         // if `arg` has side-effect, the semantic will change
                         iter_overeager_cloned::check(
                             cx,
@@ -5080,8 +5080,8 @@ impl Methods {
                         iter_filter::check(cx, expr, arg, span);
                     }
                 },
-                ("find", [arg]) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::find, [arg]) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         // if `arg` has side-effect, the semantic will change
                         iter_overeager_cloned::check(
                             cx,
@@ -5093,26 +5093,26 @@ impl Methods {
                         );
                     }
                 },
-                ("filter_map", [arg]) => {
+                (sym::filter_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                     filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
-                ("find_map", [arg]) => {
+                (sym::find_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                 },
-                ("flat_map", [arg]) => {
+                (sym::flat_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     flat_map_identity::check(cx, expr, arg, span);
                     flat_map_option::check(cx, expr, arg, span);
                 },
-                ("flatten", []) => match method_call(recv) {
-                    Some(("map", recv, [map_arg], map_span, _)) => {
+                (sym::flatten, []) => match method_call(recv) {
+                    Some((sym::map, recv, [map_arg], map_span, _)) => {
                         map_flatten::check(cx, expr, recv, map_arg, map_span);
                     },
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                    Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                         cx,
                         expr,
                         recv,
@@ -5122,15 +5122,15 @@ impl Methods {
                     ),
                     _ => {},
                 },
-                ("fold", [init, acc]) => {
+                (sym::fold, [init, acc]) => {
                     manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv);
                     unnecessary_fold::check(cx, expr, init, acc, span);
                 },
-                ("for_each", [arg]) => {
+                (sym::for_each, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     match method_call(recv) {
-                        Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
-                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                        Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
+                        Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                             cx,
                             expr,
                             recv,
@@ -5141,44 +5141,44 @@ impl Methods {
                         _ => {},
                     }
                 },
-                ("get", [arg]) => {
+                (sym::get, [arg]) => {
                     get_first::check(cx, expr, recv, arg);
                     get_last_with_len::check(cx, expr, recv, arg);
                 },
-                ("get_or_insert_with", [arg]) => {
+                (sym::get_or_insert_with, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert");
                 },
-                ("hash", [arg]) => {
+                (sym::hash, [arg]) => {
                     unit_hash::check(cx, expr, recv, arg);
                 },
-                ("is_empty", []) => {
+                (sym::is_empty, []) => {
                     match method_call(recv) {
-                        Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => {
-                            needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span);
+                        Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) => {
+                            needless_as_bytes::check(cx, prev_method, name, prev_recv, expr.span);
                         },
-                        Some(("as_str", recv, [], as_str_span, _)) => {
+                        Some((sym::as_str, recv, [], as_str_span, _)) => {
                             redundant_as_str::check(cx, expr, recv, as_str_span, span);
                         },
                         _ => {},
                     }
                     is_empty::check(cx, expr, recv);
                 },
-                ("is_file", []) => filetype_is_file::check(cx, expr, recv),
-                ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
-                ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false),
-                ("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true),
-                ("iter" | "iter_mut" | "into_iter", []) => {
+                (sym::is_file, []) => filetype_is_file::check(cx, expr, recv),
+                (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
+                (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false),
+                (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true),
+                (sym::iter | sym::iter_mut | sym::into_iter, []) => {
                     iter_on_single_or_empty_collections::check(cx, expr, name, recv);
                 },
-                ("join", [join_arg]) => {
-                    if let Some(("collect", _, _, span, _)) = method_call(recv) {
+                (sym::join, [join_arg]) => {
+                    if let Some((sym::collect, _, _, span, _)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     } else {
                         join_absolute_paths::check(cx, recv, join_arg, expr.span);
                     }
                 },
-                ("last", []) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::last, []) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5190,24 +5190,24 @@ impl Methods {
                     }
                     double_ended_iterator_last::check(cx, expr, recv, call_span);
                 },
-                ("len", []) => {
-                    if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) {
-                        needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span);
+                (sym::len, []) => {
+                    if let Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) = method_call(recv) {
+                        needless_as_bytes::check(cx, prev_method, sym::len, prev_recv, expr.span);
                     }
                 },
-                ("lock", []) => {
+                (sym::lock, []) => {
                     mut_mutex_lock::check(cx, expr, recv, span);
                 },
-                (name @ ("map" | "map_err"), [m_arg]) => {
-                    if name == "map" {
+                (name @ (sym::map | sym::map_err), [m_arg]) => {
+                    if name == sym::map {
                         unused_enumerate_index::check(cx, expr, recv, m_arg);
                         map_clone::check(cx, expr, recv, m_arg, self.msrv);
                         map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span);
                         match method_call(recv) {
-                            Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
+                            Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => {
                                 iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv);
                             },
-                            Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                            Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                                 cx,
                                 expr,
                                 recv,
@@ -5222,12 +5222,12 @@ impl Methods {
                     }
                     if let Some((name, recv2, args, span2, _)) = method_call(recv) {
                         match (name, args) {
-                            ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
-                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
-                            ("filter", [f_arg]) => {
+                            (sym::as_mut, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
+                            (sym::as_ref, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+                            (sym::filter, [f_arg]) => {
                                 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                             },
-                            ("find", [f_arg]) => {
+                            (sym::find, [f_arg]) => {
                                 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
                             },
                             _ => {},
@@ -5237,22 +5237,22 @@ impl Methods {
                     manual_inspect::check(cx, expr, m_arg, name, span, self.msrv);
                     crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
                 },
-                ("map_break" | "map_continue", [m_arg]) => {
+                (sym::map_break | sym::map_continue, [m_arg]) => {
                     crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
                 },
-                ("map_or", [def, map]) => {
+                (sym::map_or, [def, map]) => {
                     option_map_or_none::check(cx, expr, recv, def, map);
                     manual_ok_or::check(cx, expr, recv, def, map);
                     unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv);
                 },
-                ("map_or_else", [def, map]) => {
+                (sym::map_or_else, [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
                     unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
                 },
-                ("next", []) => {
+                (sym::next, []) => {
                     if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
                         match (name2, args2) {
-                            ("cloned", []) => iter_overeager_cloned::check(
+                            (sym::cloned, []) => iter_overeager_cloned::check(
                                 cx,
                                 expr,
                                 recv,
@@ -5260,19 +5260,19 @@ impl Methods {
                                 iter_overeager_cloned::Op::LaterCloned,
                                 false,
                             ),
-                            ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
-                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
-                            ("iter", []) => iter_next_slice::check(cx, expr, recv2),
-                            ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
-                            ("skip_while", [_]) => skip_while_next::check(cx, expr),
-                            ("rev", []) => manual_next_back::check(cx, expr, recv, recv2),
+                            (sym::filter, [arg]) => filter_next::check(cx, expr, recv2, arg),
+                            (sym::filter_map, [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+                            (sym::iter, []) => iter_next_slice::check(cx, expr, recv2),
+                            (sym::skip, [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
+                            (sym::skip_while, [_]) => skip_while_next::check(cx, expr),
+                            (sym::rev, []) => manual_next_back::check(cx, expr, recv, recv2),
                             _ => {},
                         }
                     }
                 },
-                ("nth", [n_arg]) => match method_call(recv) {
-                    Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                (sym::nth, [n_arg]) => match method_call(recv) {
+                    Some((sym::bytes, recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                    Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                         cx,
                         expr,
                         recv,
@@ -5280,54 +5280,54 @@ impl Methods {
                         iter_overeager_cloned::Op::LaterCloned,
                         false,
                     ),
-                    Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => {
+                    Some((iter_method @ (sym::iter | sym::iter_mut), iter_recv, [], iter_span, _)) => {
                         if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) {
                             iter_nth_zero::check(cx, expr, recv, n_arg);
                         }
                     },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
-                ("ok_or_else", [arg]) => {
+                (sym::ok_or_else, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
                 },
-                ("open", [_]) => {
+                (sym::open, [_]) => {
                     open_options::check(cx, expr, recv);
                 },
-                ("or_else", [arg]) => {
+                (sym::or_else, [arg]) => {
                     if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                     }
                 },
-                ("push", [arg]) => {
+                (sym::push, [arg]) => {
                     path_buf_push_overwrite::check(cx, expr, arg);
                 },
-                ("read_to_end", [_]) => {
+                (sym::read_to_end, [_]) => {
                     verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
                 },
-                ("read_to_string", [_]) => {
+                (sym::read_to_string, [_]) => {
                     verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
                 },
-                ("read_line", [arg]) => {
+                (sym::read_line, [arg]) => {
                     read_line_without_trim::check(cx, expr, recv, arg);
                 },
-                ("repeat", [arg]) => {
+                (sym::repeat, [arg]) => {
                     repeat_once::check(cx, expr, recv, arg);
                 },
-                (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
+                (name @ (sym::replace | sym::replacen), [arg1, arg2] | [arg1, arg2, _]) => {
                     no_effect_replace::check(cx, expr, arg1, arg2);
 
                     // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
                     if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY)
-                        && name == "replace"
-                        && let Some(("replace", ..)) = method_call(recv)
+                        && name == sym::replace
+                        && let Some((sym::replace, ..)) = method_call(recv)
                     {
                         collapsible_str_replace::check(cx, expr, arg1, arg2);
                     }
                 },
-                ("resize", [count_arg, default_arg]) => {
+                (sym::resize, [count_arg, default_arg]) => {
                     vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
                 },
-                ("seek", [arg]) => {
+                (sym::seek, [arg]) => {
                     if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) {
                         seek_from_current::check(cx, expr, recv, arg);
                     }
@@ -5335,11 +5335,11 @@ impl Methods {
                         seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
                     }
                 },
-                ("skip", [arg]) => {
+                (sym::skip, [arg]) => {
                     iter_skip_zero::check(cx, expr, arg);
                     iter_out_of_bounds::check_skip(cx, expr, recv, arg);
 
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5350,34 +5350,34 @@ impl Methods {
                         );
                     }
                 },
-                ("sort", []) => {
+                (sym::sort, []) => {
                     stable_sort_primitive::check(cx, expr, recv);
                 },
-                ("sort_by", [arg]) => {
+                (sym::sort_by, [arg]) => {
                     unnecessary_sort_by::check(cx, expr, recv, arg, false);
                 },
-                ("sort_unstable_by", [arg]) => {
+                (sym::sort_unstable_by, [arg]) => {
                     unnecessary_sort_by::check(cx, expr, recv, arg, true);
                 },
-                ("split", [arg]) => {
+                (sym::split, [arg]) => {
                     str_split::check(cx, expr, recv, arg);
                 },
-                ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
+                (sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => {
                     if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                         str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
                     }
                 },
-                ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
+                (sym::splitn_mut | sym::rsplitn_mut, [count_arg, _]) => {
                     if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                     }
                 },
-                ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
-                ("take", [arg]) => {
+                (sym::step_by, [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+                (sym::take, [arg]) => {
                     iter_out_of_bounds::check_take(cx, expr, recv, arg);
                     manual_repeat_n::check(cx, expr, recv, arg, self.msrv);
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5388,74 +5388,89 @@ impl Methods {
                         );
                     }
                 },
-                ("take", []) => needless_option_take::check(cx, expr, recv),
-                ("then", [arg]) => {
+                (sym::take, []) => needless_option_take::check(cx, expr, recv),
+                (sym::then, [arg]) => {
                     if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
                         return;
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
                 },
-                ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => {
+                (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => {
                     unnecessary_fallible_conversions::check_method(cx, expr);
                 },
-                ("to_owned", []) => {
+                (sym::to_owned, []) => {
                     if !suspicious_to_owned::check(cx, expr, recv) {
                         implicit_clone::check(cx, name, expr, recv);
                     }
                 },
-                ("to_os_string" | "to_path_buf" | "to_vec", []) => {
+                (sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => {
                     implicit_clone::check(cx, name, expr, recv);
                 },
-                ("type_id", []) => {
+                (sym::type_id, []) => {
                     type_id_on_box::check(cx, recv, expr.span);
                 },
-                ("unwrap", []) => {
+                (sym::unwrap, []) => {
                     match method_call(recv) {
-                        Some(("get", recv, [get_arg], _, _)) => {
+                        Some((sym::get, recv, [get_arg], _, _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, false);
                         },
-                        Some(("get_mut", recv, [get_arg], _, _)) => {
+                        Some((sym::get_mut, recv, [get_arg], _, _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, true);
                         },
-                        Some(("or", recv, [or_arg], or_span, _)) => {
+                        Some((sym::or, recv, [or_arg], or_span, _)) => {
                             or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or", [u_arg]) => {
+                (sym::unwrap_or, [u_arg]) => {
                     match method_call(recv) {
-                        Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
-                            manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                        Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => {
+                            manual_saturating_arithmetic::check(
+                                cx,
+                                expr,
+                                lhs,
+                                rhs,
+                                u_arg,
+                                &arith.as_str()[const { "checked_".len() }..],
+                            );
                         },
-                        Some(("map", m_recv, [m_arg], span, _)) => {
+                        Some((sym::map, m_recv, [m_arg], span, _)) => {
                             option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
                         },
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
-                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or");
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
+                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or_default", []) => {
+                (sym::unwrap_or_default, []) => {
                     match method_call(recv) {
-                        Some(("map", m_recv, [arg], span, _)) => {
+                        Some((sym::map, m_recv, [arg], span, _)) => {
                             manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv);
                         },
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
-                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default");
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
+                            obfuscated_if_else::check(
+                                cx,
+                                expr,
+                                t_recv,
+                                t_arg,
+                                None,
+                                then_method,
+                                sym::unwrap_or_default,
+                            );
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or_else", [u_arg]) => {
+                (sym::unwrap_or_else, [u_arg]) => {
                     match method_call(recv) {
-                        Some(("map", recv, [map_arg], _, _))
+                        Some((sym::map, recv, [map_arg], _, _))
                             if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
                             obfuscated_if_else::check(
                                 cx,
                                 expr,
@@ -5463,7 +5478,7 @@ impl Methods {
                                 t_arg,
                                 Some(u_arg),
                                 then_method,
-                                "unwrap_or_else",
+                                sym::unwrap_or_else,
                             );
                         },
                         _ => {
@@ -5472,13 +5487,13 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("wake", []) => {
+                (sym::wake, []) => {
                     waker_clone_wake::check(cx, expr, recv);
                 },
-                ("write", []) => {
+                (sym::write, []) => {
                     readonly_write_lock::check(cx, expr, recv);
                 },
-                ("zip", [arg]) => {
+                (sym::zip, [arg]) => {
                     if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
                     {
@@ -5490,8 +5505,8 @@ impl Methods {
         }
         // Handle method calls whose receiver and arguments may come from expansion
         if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
-            match (path.ident.name.as_str(), args) {
-                ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => {
+            match (path.ident.name, args) {
+                (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5502,7 +5517,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Expect,
                     );
                 },
-                ("expect_err", [_]) => {
+                (sym::expect_err, [_]) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5513,7 +5528,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Expect,
                     );
                 },
-                ("unwrap", []) => {
+                (sym::unwrap, []) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5524,7 +5539,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Unwrap,
                     );
                 },
-                ("unwrap_err", []) => {
+                (sym::unwrap_err, []) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5543,13 +5558,13 @@ impl Methods {
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) {
     match method_call(recv) {
-        Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) => {
+        Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => {
             search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
         },
-        Some(("get", f_recv, [arg], _, _)) => {
+        Some((sym::get, f_recv, [arg], _, _)) => {
             unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some);
         },
-        Some(("first", f_recv, [], _, _)) => {
+        Some((sym::first, f_recv, [], _, _)) => {
             unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some);
         },
         _ => {},
@@ -5593,7 +5608,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
 
 struct ShouldImplTraitCase {
     trait_name: &'static str,
-    method_name: &'static str,
+    method_name: Symbol,
     param_count: usize,
     fn_header: hir::FnHeader,
     // implicit self kind expected (none, self, &self, ...)
@@ -5606,7 +5621,7 @@ struct ShouldImplTraitCase {
 impl ShouldImplTraitCase {
     const fn new(
         trait_name: &'static str,
-        method_name: &'static str,
+        method_name: Symbol,
         param_count: usize,
         fn_header: hir::FnHeader,
         self_kind: SelfKind,
@@ -5639,36 +5654,36 @@ impl ShouldImplTraitCase {
 
 #[rustfmt::skip]
 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
-    ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
-    ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
-    ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Add", sym::add,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::clone::Clone", sym::clone,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::default::Default", kw::Default,  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Deref", sym::deref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::Div", sym::div,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Drop", sym::drop,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
+    ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::str::FromStr", sym::from_str,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::hash::Hash", sym::hash,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::ops::Index", sym::index,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut,  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Mul", sym::mul,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Neg", sym::neg,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::iter::Iterator", sym::next,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
+    ShouldImplTraitCase::new("std::ops::Not", sym::not,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Rem", sym::rem,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shl", sym::shl,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shr", sym::shr,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Sub", sym::sub,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 ];
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
index 7c9f7bae990..635d06330e0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
@@ -4,11 +4,11 @@ use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 use super::NEEDLESS_AS_BYTES;
 
-pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) {
+pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) {
     let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs();
     if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() {
         let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
index 538aa9097a4..d77d044340d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
@@ -1,22 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::path_res;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::{path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_hir::def::Res;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 use super::NEEDLESS_OPTION_AS_DEREF;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: Symbol) {
     let typeck = cx.typeck_results();
     let outer_ty = typeck.expr_ty(expr);
 
     if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
-        if name == "as_deref_mut" && recv.is_syntactic_place_expr() {
+        if name == sym::as_deref_mut && recv.is_syntactic_place_expr() {
             let Res::Local(binding_id) = path_res(cx, recv) else {
                 return;
             };
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
index cd1b97f3c51..1544a12e6ba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::NEEDLESS_OPTION_TAKE;
 
@@ -42,20 +42,20 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// When this function is called, we are reasonably certain that the `ExprKind` is either
 /// `Call` or `MethodCall` because we already checked that the expression is not
 /// `is_syntactic_place_expr()`.
-fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> {
+fn source_of_temporary_value(expr: &Expr<'_>) -> Option<Symbol> {
     match expr.peel_borrows().kind {
         ExprKind::Call(function, _) => {
             if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind
                 && !func_path.segments.is_empty()
             {
-                return Some(func_path.segments[0].ident.name.as_str());
+                return Some(func_path.segments[0].ident.name);
             }
             if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind {
-                return Some(func_path_segment.ident.name.as_str());
+                return Some(func_path_segment.ident.name);
             }
             None
         },
-        ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()),
+        ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index 1cc56de4876..604b48656ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -1,13 +1,14 @@
 use super::OBFUSCATED_IF_ELSE;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
-use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::ExprKind;
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -15,8 +16,8 @@ pub(super) fn check<'tcx>(
     then_recv: &'tcx hir::Expr<'_>,
     then_arg: &'tcx hir::Expr<'_>,
     unwrap_arg: Option<&'tcx hir::Expr<'_>>,
-    then_method_name: &str,
-    unwrap_method_name: &str,
+    then_method_name: Symbol,
+    unwrap_method_name: Symbol,
 ) {
     let recv_ty = cx.typeck_results().expr_ty(then_recv);
 
@@ -31,25 +32,25 @@ pub(super) fn check<'tcx>(
         };
 
         let if_then = match then_method_name {
-            "then" if let ExprKind::Closure(closure) = then_arg.kind => {
+            sym::then if let ExprKind::Closure(closure) = then_arg.kind => {
                 let body = cx.tcx.hir_body(closure.body);
                 snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
             },
-            "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
+            sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
             _ => return,
         };
 
         // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
         let els = match unwrap_method_name {
-            "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
-            "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
+            sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
+            sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
                 let body = cx.tcx.hir_body(closure.body);
                 snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
             },
-            "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
+            sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
                 snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
             },
-            "unwrap_or_default" => "Default::default()".into(),
+            sym::unwrap_or_default => "Default::default()".into(),
             _ => return,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
index 9b22494888f..3c38deca6cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
@@ -1,14 +1,16 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use super::{OPTION_AS_REF_CLONED, method_call};
 
 pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
-    if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv)
+    if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) =
+        method_call(cloned_recv)
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
     {
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index b78b082e460..38cb4d51ca0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -12,7 +12,7 @@ use rustc_errors::Applicability;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
-use rustc_span::symbol::{self, Symbol};
+use rustc_span::Symbol;
 use {rustc_ast as ast, rustc_hir as hir};
 
 use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
     method_span: Span,
-    name: &str,
+    name: Symbol,
     receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
     /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
-        name: &str,
+        name: Symbol,
         receiver: &hir::Expr<'_>,
         fun: &hir::Expr<'_>,
         call_expr: Option<&hir::Expr<'_>>,
@@ -66,8 +66,8 @@ pub(super) fn check<'tcx>(
         };
 
         let sugg = match (name, call_expr.is_some()) {
-            ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default,
-            ("or_insert", true) | ("or_insert_with", false) => sym::or_default,
+            (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default,
+            (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default,
             _ => return false,
         };
 
@@ -126,7 +126,7 @@ pub(super) fn check<'tcx>(
     #[expect(clippy::too_many_arguments)]
     fn check_or_fn_call<'tcx>(
         cx: &LateContext<'tcx>,
-        name: &str,
+        name: Symbol,
         method_span: Span,
         self_expr: &hir::Expr<'_>,
         arg: &'tcx hir::Expr<'_>,
@@ -137,11 +137,16 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) -> bool {
         // (path, fn_has_argument, methods, suffix)
-        const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
-            (sym::BTreeEntry, false, &["or_insert"], "with"),
-            (sym::HashMapEntry, false, &["or_insert"], "with"),
-            (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
-            (sym::Result, true, &["or", "unwrap_or"], "else"),
+        const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [
+            (sym::BTreeEntry, false, &[sym::or_insert], "with"),
+            (sym::HashMapEntry, false, &[sym::or_insert], "with"),
+            (
+                sym::Option,
+                false,
+                &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or],
+                "else",
+            ),
+            (sym::Result, true, &[sym::or, sym::unwrap_or], "else"),
         ];
 
         if KNOW_TYPES.iter().any(|k| k.2.contains(&name))
@@ -260,7 +265,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>)
             && ident.name == sym::to_string
             && let hir::Expr { kind, .. } = self_arg
             && let hir::ExprKind::Lit(lit) = kind
-            && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+            && let ast::LitKind::Str(rustc_span::sym::empty, _) = lit.node
         {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 97c8ce2bcdd..855babb797a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -2,14 +2,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::deref_closure_args;
 use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs};
+use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym};
 use hir::ExprKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::PatKind;
 use rustc_lint::LateContext;
-use rustc_span::Span;
-use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 
 use super::SEARCH_IS_SOME;
 
@@ -19,7 +18,7 @@ use super::SEARCH_IS_SOME;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'_>,
     expr: &'tcx hir::Expr<'_>,
-    search_method: &str,
+    search_method: Symbol,
     is_some: bool,
     search_recv: &hir::Expr<'_>,
     search_arg: &'tcx hir::Expr<'_>,
@@ -35,7 +34,7 @@ pub(super) fn check<'tcx>(
             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
             let mut applicability = Applicability::MachineApplicable;
-            let any_search_snippet = if search_method == "find"
+            let any_search_snippet = if search_method == sym::find
                 && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
                 && let closure_body = cx.tcx.hir_body(body)
                 && let Some(closure_arg) = closure_body.params.first()
@@ -107,7 +106,7 @@ pub(super) fn check<'tcx>(
         }
     }
     // lint if `find()` is called by `String` or `&str`
-    else if search_method == "find" {
+    else if search_method == sym::find {
         let is_string_or_str_slice = |e| {
             let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
             if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
index fb4ac7b3613..479064a0671 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
     // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most
     // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
     if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind
-        && trim_method_name.ident.as_str() == "trim"
+        && trim_method_name.ident.name == sym::trim
         && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
         && !is_const_evaluatable(cx, trim_recv)
         && let ExprKind::Lit(split_lit) = split_arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index c8efb600f57..6935ae1f391 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::visitors::{Descend, for_each_expr};
-use clippy_utils::{is_diag_item_method, path_to_local_id, paths};
+use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
@@ -12,13 +12,13 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::{Span, Symbol, SyntaxContext, sym};
+use rustc_span::{Span, Symbol, SyntaxContext};
 
 use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
 
 pub(super) fn check(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
@@ -45,9 +45,9 @@ pub(super) fn check(
     }
 }
 
-fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
+fn lint_needless(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
     let mut app = Applicability::MachineApplicable;
-    let r = if method_name == "splitn" { "" } else { "r" };
+    let r = if method_name == sym::splitn { "" } else { "r" };
 
     span_lint_and_sugg(
         cx,
@@ -66,14 +66,14 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
 
 fn check_manual_split_once(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
     usage: &IterUsage,
 ) {
     let ctxt = expr.span.ctxt();
-    let (msg, reverse) = if method_name == "splitn" {
+    let (msg, reverse) = if method_name == sym::splitn {
         ("manual implementation of `split_once`", false)
     } else {
         ("manual implementation of `rsplit_once`", true)
@@ -121,7 +121,7 @@ fn check_manual_split_once(
 /// ```
 fn check_manual_split_once_indirect(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
@@ -143,7 +143,7 @@ fn check_manual_split_once_indirect(
         && first.name != second.name
         && !local_used_after_expr(cx, iter_binding_id, second.init_expr)
     {
-        let (r, lhs, rhs) = if method_name == "splitn" {
+        let (r, lhs, rhs) = if method_name == sym::splitn {
             ("", first.name, second.name)
         } else {
             ("r", second.name, first.name)
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index c7885f689d7..f11a41f90f1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::method_chain_args;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{method_chain_args, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
         return;
     }
-    if let Some(arglists) = method_chain_args(arg, &["chars"]) {
+    if let Some(arglists) = method_chain_args(arg, &[sym::chars]) {
         let target = &arglists[0].0;
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if self_ty.is_str() {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index ff5c1d1a401..f8b6d4349fb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_note;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 use rustc_span::source_map::Spanned;
 
 use super::SUSPICIOUS_SPLITN;
 
-pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
+pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
     if count <= 1
         && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(call_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 79ed352193f..d260e0ef6e1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -9,10 +9,16 @@ use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
+use rustc_span::Symbol;
 
 use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    arg: &'tcx hir::Expr<'tcx>,
+    name: Symbol,
+) {
     if !is_trait_method(cx, expr, sym::Iterator) {
         return;
     }
@@ -38,7 +44,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
         let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
         let sugg = if !found_filtering {
             // Check if the closure is .filter_map(|x| Some(x))
-            if name == "filter_map"
+            if name == sym::filter_map
                 && let hir::ExprKind::Call(expr, args) = body.value.kind
                 && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
                 && let hir::ExprKind::Path(_) = args[0].kind
@@ -51,7 +57,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 );
                 return;
             }
-            if name == "filter_map" {
+            if name == sym::filter_map {
                 "map(..)"
             } else {
                 "map(..).next()"
@@ -61,7 +67,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 ty::Adt(adt, subst)
                     if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
                 {
-                    if name == "filter_map" { "filter(..)" } else { "find(..)" }
+                    if name == sym::filter_map {
+                        "filter(..)"
+                    } else {
+                        "find(..)"
+                    }
                 },
                 _ => return,
             }
@@ -70,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
         };
         span_lint(
             cx,
-            if name == "filter_map" {
+            if name == sym::filter_map {
                 UNNECESSARY_FILTER_MAP
             } else {
                 UNNECESSARY_FIND_MAP
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index fa3a29e3667..cc4448192d3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res};
+use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_span::Symbol;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
@@ -25,7 +26,7 @@ pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
     recv: &hir::Expr<'_>,
-    method: &str,
+    method: Symbol,
     args: &[hir::Expr<'_>],
 ) {
     let init = clippy_utils::expr_or_init(cx, recv);
@@ -42,17 +43,17 @@ pub(super) fn check(
         let res = cx.qpath_res(qpath, call.hir_id());
 
         if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) {
-            ("Some", call_args, get_ty_from_args(args, 0))
+            (sym::Some, call_args, get_ty_from_args(args, 0))
         } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) {
-            ("Ok", call_args, get_ty_from_args(args, 0))
+            (sym::Ok, call_args, get_ty_from_args(args, 0))
         } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) {
-            ("Err", call_args, get_ty_from_args(args, 1))
+            (sym::Err, call_args, get_ty_from_args(args, 1))
         } else {
             return;
         }
     } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
         let call_args: &[hir::Expr<'_>] = &[];
-        ("None", call_args, None)
+        (sym::None, call_args, None)
     } else {
         return;
     };
@@ -62,12 +63,12 @@ pub(super) fn check(
 
     span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| {
         let suggestions = match (constructor, method, ty) {
-            ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]),
-            ("None", "expect", _) => Some(vec![
+            (sym::None, sym::unwrap, _) => Some(vec![(expr.span, "panic!()".to_string())]),
+            (sym::None, sym::expect, _) => Some(vec![
                 (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
                 (expr.span.with_lo(args[0].span.hi()), ")".to_string()),
             ]),
-            ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => {
+            (sym::Some | sym::Ok, sym::unwrap_unchecked, _) | (sym::Err, sym::unwrap_err_unchecked, _) => {
                 let mut suggs = vec![
                     (recv.span.with_hi(call_args[0].span.lo()), String::new()),
                     (expr.span.with_lo(call_args[0].span.hi()), String::new()),
@@ -83,7 +84,7 @@ pub(super) fn check(
                 }
                 Some(suggs)
             },
-            ("None", "unwrap_or_default", _) => {
+            (sym::None, sym::unwrap_or_default, _) => {
                 let ty = cx.typeck_results().expr_ty(expr);
                 let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
                     with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
@@ -92,11 +93,11 @@ pub(super) fn check(
                 };
                 Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
             },
-            ("None", "unwrap_or", _) => Some(vec![
+            (sym::None, sym::unwrap_or, _) => Some(vec![
                 (expr.span.with_hi(args[0].span.lo()), String::new()),
                 (expr.span.with_lo(args[0].span.hi()), String::new()),
             ]),
-            ("None", "unwrap_or_else", _) => match args[0].kind {
+            (sym::None, sym::unwrap_or_else, _) => match args[0].kind {
                 hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
                     (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()),
                     (expr.span.with_lo(args[0].span.hi()), String::new()),
@@ -105,14 +106,14 @@ pub(super) fn check(
             },
             _ if call_args.is_empty() => None,
             (_, _, Some(_)) => None,
-            ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
+            (sym::Ok, sym::unwrap_err, None) | (sym::Err, sym::unwrap, None) => Some(vec![
                 (
                     recv.span.with_hi(call_args[0].span.lo()),
                     "panic!(\"{:?}\", ".to_string(),
                 ),
                 (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()),
             ]),
-            ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![
+            (sym::Ok, sym::expect_err, None) | (sym::Err, sym::expect, None) => Some(vec![
                 (
                     recv.span.with_hi(call_args[0].span.lo()),
                     "panic!(\"{1}: {:?}\", ".to_string(),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
index 7d01bdc2269..413881d5ec9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -5,16 +5,17 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
-    name: &str,
+    name: Symbol,
     recv: &'tcx Expr<'_>,
     arg: &'tcx Expr<'_>,
 ) {
@@ -47,10 +48,10 @@ pub(super) fn check<'tcx>(
     }
 }
 
-fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) {
+fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: Symbol, lhs: Span, rhs: Span, order: Ordering) {
     let cmp_str = if order.is_ge() { "smaller" } else { "greater" };
 
-    let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) {
+    let suggested_value = if (name == sym::min && order.is_ge()) || (name == sym::max && order.is_le()) {
         snippet(cx, rhs, "..")
     } else {
         snippet(cx, lhs, "..")
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 87bb8d46a1d..29a0d2950bc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -619,7 +619,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
 fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
-    is_clone_like(cx, method_name.as_str(), method_def_id)
+    is_clone_like(cx, method_name, method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
 }
@@ -655,11 +655,18 @@ fn is_to_string_on_string_like<'a>(
     }
 }
 
-fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::HashSet)
-        || is_type_diagnostic_item(cx, ty, sym::HashMap)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeSet)
+fn std_map_key<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    match ty.kind() {
+        ty::Adt(adt, args)
+            if matches!(
+                cx.tcx.get_diagnostic_name(adt.did()),
+                Some(sym::BTreeMap | sym::BTreeSet | sym::HashMap | sym::HashSet)
+            ) =>
+        {
+            Some(args.type_at(0))
+        },
+        _ => None,
+    }
 }
 
 fn is_str_and_string(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool {
@@ -679,11 +686,11 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
     if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind
         && let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind
         && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && let method_name = method_path.ident.name.as_str()
+        && let method_name = method_path.ident.name
         && match method_name {
-            "to_owned" => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id),
-            "to_string" => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
-            "to_vec" => cx
+            sym::to_owned => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id),
+            sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
+            sym::to_vec => cx
                 .tcx
                 .impl_of_method(method_def_id)
                 .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice())
@@ -721,6 +728,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
 // 1. This is a method with only one argument that doesn't come from a trait.
 // 2. That it has `Borrow` in its generic predicates.
 // 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`).
+// 4. The key to the "map type" is not a reference.
 fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind
         && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
@@ -738,7 +746,9 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         })
         && let caller_ty = cx.typeck_results().expr_ty(caller)
         // For now we limit it to "map types".
-        && is_a_std_map_type(cx, caller_ty)
+        && let Some(key_ty) = std_map_key(cx, caller_ty)
+        // We need to check that the key type is not a reference.
+        && !key_ty.is_ref()
     {
         check_if_applicable_to_argument(cx, &arg);
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 17e2620d9dd..d30c12e0c48 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use core::ops::ControlFlow;
 
@@ -39,7 +39,7 @@ fn get_enum_ty(enum_ty: Ty<'_>) -> Option<Ty<'_>> {
 }
 
 /// Checks for the `USELESS_ASREF` lint.
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
     let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
@@ -79,9 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
                 applicability,
             );
         }
-    } else if let Some(impl_id) = cx.tcx.opt_parent(def_id)
+    } else if let Some(impl_id) = cx.tcx.impl_of_method(def_id)
         && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def()
-        && (cx.tcx.lang_items().option_type() == Some(adt.did()) || cx.tcx.is_diagnostic_item(sym::Result, adt.did()))
+        && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result))
     {
         let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs();
         let res_ty = cx.typeck_results().expr_ty(expr).peel_refs();
@@ -161,7 +161,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
     }
 }
 
-fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) {
+fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: Symbol) {
     let mut applicability = Applicability::MachineApplicable;
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 7384e534ed7..ad9b3c36454 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_copy;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::fmt;
 
 use super::WRONG_SELF_CONVENTION;
@@ -83,17 +83,18 @@ impl fmt::Display for Convention {
 #[allow(clippy::too_many_arguments)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    item_name: &str,
+    item_name: Symbol,
     self_ty: Ty<'tcx>,
     first_arg_ty: Ty<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
 ) {
+    let item_name_str = item_name.as_str();
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
-            .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item))
+            .all(|conv| conv.check(cx, self_ty, item_name_str, implements_trait, is_trait_item))
     }) {
         // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032)
         if implements_trait
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 f3e24044fb6..a6be7581c9a 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
@@ -7,7 +7,7 @@ use rustc_abi::ExternAbi;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
+use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind, OwnerId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                 }
             },
             FnKind::Method(_, sig, ..) => {
-                if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() {
+                if already_const(sig.header) || trait_ref_of_method(cx, OwnerId { def_id }).is_some() {
                     return;
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index a45031ce22b..98a9a98d281 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
         {
             self.check_sig(cx, item.owner_id.def_id, sig.decl);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index f768e11a4a2..3ed4b1c2ea9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt,
-    is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+    is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, sym,
 };
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -320,7 +320,7 @@ fn check_comparison<'a, 'tcx>(
             cx.typeck_results().expr_ty(left_side),
             cx.typeck_results().expr_ty(right_side),
         );
-        if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() {
+        if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() {
             return;
         }
         if l_ty.is_bool() && r_ty.is_bool() {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 275d710c76a..95623467b81 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     }
 
                     if is_type_diagnostic_item(cx, ty, sym::Vec)
-                        && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")])
+                        && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[(sym::clone, ".to_owned()")])
                         && let TyKind::Path(QPath::Resolved(_, path)) = input.kind
                         && let Some(elem_ty) = path
                             .segments
@@ -253,8 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     }
 
                     if is_type_lang_item(cx, ty, LangItem::String)
-                        && let Some(clone_spans) =
-                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")])
+                        && let Some(clone_spans) = get_spans(
+                            cx,
+                            Some(body.id()),
+                            idx,
+                            &[(sym::clone, ".to_string()"), (sym::as_str, "")],
+                        )
                     {
                         diag.span_suggestion(
                             input.span,
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 7ab7976d569..02c48166131 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -221,10 +221,16 @@ fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 }
 
+/// Checks if dropping `expr` might have a visible side effect.
+fn expr_ty_has_significant_drop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    ty.has_significant_drop(cx.tcx, cx.typing_env())
+}
+
 fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
-        ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
+        ExprKind::Path(..) => !expr_ty_has_significant_drop(cx, expr),
         ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
         ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
         ExprKind::Repeat(inner, _)
@@ -233,8 +239,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         | ExprKind::Unary(_, inner)
         | ExprKind::Field(inner, _)
         | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner),
-        ExprKind::Struct(_, fields, ref base) => {
-            !has_drop(cx, cx.typeck_results().expr_ty(expr))
+        ExprKind::Struct(_, fields, base) => {
+            !expr_ty_has_significant_drop(cx, expr)
                 && fields.iter().all(|field| has_no_effect(cx, field.expr))
                 && match &base {
                     StructTailExpr::None | StructTailExpr::DefaultFields(_) => true,
@@ -252,7 +258,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
                 );
                 if def_matched || is_range_literal(expr) {
-                    !has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+                    !expr_ty_has_significant_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
                 } else {
                     false
                 }
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 6d3e77b6b6e..a27c6aa75e3 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -1,56 +1,78 @@
-use std::ptr;
+// Implementation for lints detecting interior mutability in constants.
+//
+// For `declare_interior_mutable_const` there are three strategies used to
+// determine if a value has interior mutability:
+// * A type-based check. This is the least accurate, but can always run.
+// * A const-eval based check. This is the most accurate, but this requires that the value is
+//   defined and does not work with generics.
+// * A HIR-tree based check. This is less accurate than const-eval, but it can be applied to generic
+//   values.
+//
+// For `borrow_interior_mutable_const` the same three strategies are applied
+// when checking a constant's value, but field and array index projections at
+// the borrow site are taken into account as well. As an example: `FOO.bar` may
+// have interior mutability, but `FOO.baz` may not. When borrowing `FOO.baz` no
+// warning will be issued.
+//
+// No matter the lint or strategy, a warning should only be issued if a value
+// definitely contains interior mutability.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::ty::{InteriorMut, implements_trait};
-use rustc_abi::VariantIdx;
+use clippy_utils::paths::{PathNS, lookup_path_str};
+use clippy_utils::ty::{get_field_idx_by_name, implements_trait};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{
-    BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
+    Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::mir::{ConstValue, UnevaluatedConst};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::{
+    self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
+    TypeckResults, TypingEnv,
 };
-use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo};
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::{DUMMY_SP, sym};
+use std::collections::hash_map::Entry;
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for declaration of `const` items which is interior
-    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+    /// Checks for the declaration of named constant which contain interior mutability.
     ///
     /// ### Why is this bad?
-    /// Consts are copied everywhere they are referenced, i.e.,
-    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-    /// these types in the first place.
+    /// Named constants are copied at every use site which means any change to their value
+    /// will be lost after the newly created value is dropped. e.g.
     ///
-    /// The `const` should better be replaced by a `static` item if a global
-    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+    /// ```rust
+    /// use core::sync::atomic::{AtomicUsize, Ordering};
+    /// const ATOMIC: AtomicUsize = AtomicUsize::new(0);
+    /// fn add_one() -> usize {
+    ///     // This will always return `0` since `ATOMIC` is copied before it's used.
+    ///     ATOMIC.fetch_add(1, Ordering::AcqRel)
+    /// }
+    /// ```
     ///
-    /// ### Known problems
-    /// A "non-constant" const item is a legacy way to supply an
-    /// initialized value to downstream `static` items (e.g., the
-    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
-    /// and this lint should be suppressed.
+    /// If shared modification of the value is desired, a `static` item is needed instead.
+    /// If that is not desired, a `const fn` constructor should be used to make it obvious
+    /// at the use site that a new value is created.
     ///
-    /// Even though the lint avoids triggering on a constant whose type has enums that have variants
-    /// with interior mutability, and its value uses non interior mutable variants (see
-    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
-    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
-    /// it complains about associated constants without default values only based on its types;
-    /// which might not be preferable.
-    /// There're other enums plus associated constants cases that the lint cannot handle.
+    /// ### Known problems
+    /// Prior to `const fn` stabilization this was the only way to provide a value which
+    /// could initialize a `static` item (e.g. the `std::sync::ONCE_INIT` constant). In
+    /// this case the use of `const` is required and this lint should be suppressed.
     ///
-    /// Types that have underlying or potential interior mutability trigger the lint whether
-    /// the interior mutable field is used or not. See issue
-    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812)
+    /// There also exists types which contain private fields with interior mutability, but
+    /// no way to both create a value as a constant and modify any mutable field using the
+    /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to
+    /// scan a crate's interface to see if this is the case, all such types will be linted.
+    /// If this happens use the `ignore-interior-mutability` configuration option to allow
+    /// the type.
     ///
     /// ### Example
     /// ```no_run
@@ -74,20 +96,44 @@ declare_clippy_lint! {
     "declaring `const` with interior mutability"
 }
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks if `const` items which is interior mutable (e.g.,
-    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+    /// Checks for a borrow of a named constant with interior mutability.
     ///
     /// ### Why is this bad?
-    /// Consts are copied everywhere they are referenced, i.e.,
-    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-    /// these types in the first place.
+    /// Named constants are copied at every use site which means any change to their value
+    /// will be lost after the newly created value is dropped. e.g.
+    ///
+    /// ```rust
+    /// use core::sync::atomic::{AtomicUsize, Ordering};
+    /// const ATOMIC: AtomicUsize = AtomicUsize::new(0);
+    /// fn add_one() -> usize {
+    ///     // This will always return `0` since `ATOMIC` is copied before it's borrowed
+    ///     // for use by `fetch_add`.
+    ///     ATOMIC.fetch_add(1, Ordering::AcqRel)
+    /// }
+    /// ```
     ///
-    /// The `const` value should be stored inside a `static` item.
+    /// ### Known problems
+    /// This lint does not, and cannot in general, determine if the borrow of the constant
+    /// is used in a way which causes a mutation. e.g.
+    ///
+    /// ```rust
+    /// use core::cell::Cell;
+    /// const CELL: Cell<usize> = Cell::new(0);
+    /// fn get_cell() -> Cell<usize> {
+    ///     // This is fine. It borrows a copy of `CELL`, but never mutates it through the
+    ///     // borrow.
+    ///     CELL.clone()
+    /// }
+    /// ```
+    ///
+    /// There also exists types which contain private fields with interior mutability, but
+    /// no way to both create a value as a constant and modify any mutable field using the
+    /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to
+    /// scan a crate's interface to see if this is the case, all such types will be linted.
+    /// If this happens use the `ignore-interior-mutability` configuration option to allow
+    /// the type.
     ///
     /// ### Example
     /// ```no_run
@@ -113,60 +159,101 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-#[derive(Copy, Clone)]
-enum Source<'tcx> {
-    Item { item: Span, ty: Ty<'tcx> },
-    Assoc { item: Span },
-    Expr { expr: Span },
+#[derive(Clone, Copy)]
+enum IsFreeze {
+    /// The type and all possible values are `Freeze`
+    Yes,
+    /// The type itself is non-`Freeze`, but not all values are.
+    Maybe,
+    /// The type and all possible values are non-`Freeze`
+    No,
 }
+impl IsFreeze {
+    /// Merges the variants of a sum type (i.e. an enum).
+    fn from_variants(iter: impl Iterator<Item = Self>) -> Self {
+        iter.fold(Self::Yes, |x, y| match (x, y) {
+            (Self::Maybe, _) | (_, Self::Maybe) | (Self::No, Self::Yes) | (Self::Yes, Self::No) => Self::Maybe,
+            (Self::No, Self::No) => Self::No,
+            (Self::Yes, Self::Yes) => Self::Yes,
+        })
+    }
 
-impl Source<'_> {
-    #[must_use]
-    fn lint(&self) -> (&'static Lint, &'static str, Span) {
-        match self {
-            Self::Item { item, .. } | Self::Assoc { item, .. } => (
-                DECLARE_INTERIOR_MUTABLE_CONST,
-                "a `const` item should not be interior mutable",
-                *item,
-            ),
-            Self::Expr { expr } => (
-                BORROW_INTERIOR_MUTABLE_CONST,
-                "a `const` item with interior mutability should not be borrowed",
-                *expr,
-            ),
-        }
+    /// Merges the fields of a product type (e.g. a struct or tuple).
+    fn from_fields(mut iter: impl Iterator<Item = Self>) -> Self {
+        iter.try_fold(Self::Yes, |x, y| match (x, y) {
+            (Self::No, _) | (_, Self::No) => None,
+            (Self::Maybe, _) | (_, Self::Maybe) => Some(Self::Maybe),
+            (Self::Yes, Self::Yes) => Some(Self::Yes),
+        })
+        .unwrap_or(Self::No)
+    }
+
+    /// Checks if this is definitely `Freeze`.
+    fn is_freeze(self) -> bool {
+        matches!(self, Self::Yes)
+    }
+
+    /// Checks if this is definitely not `Freeze`.
+    fn is_not_freeze(self) -> bool {
+        matches!(self, Self::No)
     }
 }
 
-fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
-    let (lint, msg, span) = source.lint();
-    span_lint_and_then(cx, lint, span, msg, |diag| {
-        if span.from_expansion() {
-            return; // Don't give suggestions into macros.
-        }
-        match source {
-            Source::Item { ty, .. } => {
-                let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
-                    return;
-                };
-                if implements_trait(cx, ty, sync_trait, &[]) {
-                    diag.help("consider making this a static item");
-                } else {
-                    diag.help(
-                        "consider making this `Sync` so that it can go in a static item or using a `thread_local`",
-                    );
-                }
-            },
-            Source::Assoc { .. } => (),
-            Source::Expr { .. } => {
-                diag.help("assign this const to a local or static variable, and use the variable here");
+/// What operation caused a borrow to occur.
+#[derive(Clone, Copy)]
+enum BorrowCause {
+    Borrow,
+    Deref,
+    Index,
+    AutoDeref,
+    AutoBorrow,
+    AutoDerefField,
+}
+impl BorrowCause {
+    fn note(self) -> Option<&'static str> {
+        match self {
+            Self::Borrow => None,
+            Self::Deref => Some("this deref expression is a call to `Deref::deref`"),
+            Self::Index => Some("this index expression is a call to `Index::index`"),
+            Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"),
+            Self::AutoBorrow => Some("there is a compiler inserted borrow here"),
+            Self::AutoDerefField => {
+                Some("there is a compiler inserted call to `Deref::deref` when accessing this field")
             },
         }
-    });
+    }
+}
+
+/// The source of a borrow. Both what caused it and where.
+struct BorrowSource<'tcx> {
+    expr: &'tcx Expr<'tcx>,
+    cause: BorrowCause,
+}
+impl<'tcx> BorrowSource<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, expr: &'tcx Expr<'tcx>, cause: BorrowCause) -> Self {
+        // Custom deref and index impls will always have an auto-borrow inserted since we
+        // never work with reference types.
+        let (expr, cause) = if matches!(cause, BorrowCause::AutoBorrow)
+            && let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
+        {
+            match parent.kind {
+                ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref),
+                ExprKind::Index(..) => (parent, BorrowCause::Index),
+                ExprKind::Field(..) => (parent, BorrowCause::AutoDerefField),
+                _ => (expr, cause),
+            }
+        } else {
+            (expr, cause)
+        };
+        Self { expr, cause }
+    }
 }
 
 pub struct NonCopyConst<'tcx> {
-    interior_mut: InteriorMut<'tcx>,
+    ignore_tys: DefIdSet,
+    // Cache checked types. We can recurse through a type multiple times so this
+    // can be hit quite frequently.
+    freeze_tys: FxHashMap<Ty<'tcx>, IsFreeze>,
 }
 
 impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
@@ -174,332 +261,629 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE
 impl<'tcx> NonCopyConst<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability),
+            ignore_tys: conf
+                .ignore_interior_mutability
+                .iter()
+                .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty))
+                .collect(),
+            freeze_tys: FxHashMap::default(),
         }
     }
 
-    fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
-        // No branch that we check (yet) should continue if val isn't a branch
-        let Some(branched_val) = val.try_to_branch() else {
-            return false;
-        };
-        match *ty.kind() {
-            // the fact that we have to dig into every structs to search enums
-            // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
-            // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
-            // contained value.
-            ty::Adt(def, ..) if def.is_union() => false,
-            ty::Array(ty, _) => branched_val
-                .iter()
-                .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Adt(def, args) if def.is_enum() => {
-                let Some((&variant_valtree, fields)) = branched_val.split_first() else {
-                    return false;
-                };
-                let variant_index = variant_valtree.unwrap_leaf();
-                let variant_index = VariantIdx::from_u32(variant_index.to_u32());
-                fields
-                    .iter()
-                    .copied()
-                    .zip(
-                        def.variants()[variant_index]
+    /// Checks if a value of the given type is `Freeze`, or may be depending on the value.
+    fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.freeze_tys.entry(ty) {
+            Entry::Occupied(e) => *e.get(),
+            Entry::Vacant(e) => {
+                let e = e.insert(IsFreeze::Yes);
+                if ty.is_freeze(tcx, typing_env) {
+                    return IsFreeze::Yes;
+                }
+                let is_freeze = match *ty.kind() {
+                    ty::Adt(adt, _) if adt.is_unsafe_cell() => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                    ty::Adt(adt, _) if self.ignore_tys.contains(&adt.did()) => return IsFreeze::Yes,
+                    ty::Adt(adt, args) if adt.is_enum() => IsFreeze::from_variants(adt.variants().iter().map(|v| {
+                        IsFreeze::from_fields(
+                            v.fields
+                                .iter()
+                                .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                        )
+                    })),
+                    // Workaround for `ManuallyDrop`-like unions.
+                    ty::Adt(adt, args)
+                        if adt.is_union()
+                            && adt.non_enum_variant().fields.iter().any(|f| {
+                                tcx.layout_of(typing_env.as_query_input(f.ty(tcx, args)))
+                                    .is_ok_and(|l| l.layout.size().bytes() == 0)
+                            }) =>
+                    {
+                        return IsFreeze::Yes;
+                    },
+                    // Rust doesn't have the concept of an active union field so we have
+                    // to treat all fields as active.
+                    ty::Adt(adt, args) => IsFreeze::from_fields(
+                        adt.non_enum_variant()
                             .fields
                             .iter()
-                            .map(|field| field.ty(cx.tcx, args)),
-                    )
-                    .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
-            },
-            ty::Adt(def, args) => branched_val
-                .iter()
-                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
-                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Tuple(tys) => branched_val
-                .iter()
-                .zip(tys)
-                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
-                Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty),
-                _ => false,
+                            .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                    ),
+                    ty::Array(ty, _) | ty::Pat(ty, _) => self.is_ty_freeze(tcx, typing_env, ty),
+                    ty::Tuple(tys) => {
+                        IsFreeze::from_fields(tys.iter().map(|ty| self.is_ty_freeze(tcx, typing_env, ty)))
+                    },
+                    // Treat type parameters as though they were `Freeze`.
+                    ty::Param(_) | ty::Alias(..) => return IsFreeze::Yes,
+                    // TODO: check other types.
+                    _ => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                };
+                if !is_freeze.is_freeze() {
+                    self.freeze_tys.insert(ty, is_freeze);
+                }
+                is_freeze
             },
-            _ => false,
         }
     }
 
-    fn is_value_unfrozen_raw(
-        cx: &LateContext<'tcx>,
-        result: Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>,
+    /// Checks if the given constant value is `Freeze`. Returns `Err` if the constant
+    /// cannot be read, but the result depends on the value.
+    fn is_value_freeze(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
         ty: Ty<'tcx>,
-    ) -> bool {
-        result.map_or_else(
-            |err| {
-                // Consider `TooGeneric` cases as being unfrozen.
-                // This causes a false positive where an assoc const whose type is unfrozen
-                // have a value that is a frozen variant with a generic param (an example is
-                // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
-                // However, it prevents a number of false negatives that is, I think, important:
-                // 1. assoc consts in trait defs referring to consts of themselves (an example is
-                //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
-                // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
-                //    defs (i.e. without substitute for `Self`). (e.g. borrowing
-                //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
-                // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
-                //    enums. (An example is
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
-                // One might be able to prevent these FNs correctly, and replace this with `false`;
-                // e.g. implementing `has_frozen_variant` described above, and not running this function
-                // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
-                // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-                // similar to 2., but with a frozen variant) (e.g. borrowing
-                // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
-                // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
-                matches!(err, ErrorHandled::TooGeneric(..))
+        val: ConstValue<'tcx>,
+    ) -> Result<bool, ()> {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => Ok(true),
+            IsFreeze::Maybe if matches!(ty.kind(), ty::Adt(..) | ty::Array(..) | ty::Tuple(..)) => {
+                for &(val, ty) in tcx
+                    .try_destructure_mir_constant_for_user_output(val, ty)
+                    .ok_or(())?
+                    .fields
+                {
+                    if !self.is_value_freeze(tcx, typing_env, ty, val)? {
+                        return Ok(false);
+                    }
+                }
+                Ok(true)
             },
-            |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)),
-        )
-    }
-
-    fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
-        let def_id = body_id.hir_id.owner.to_def_id();
-        let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
-        let instance = ty::Instance::new_raw(def_id, args);
-        let cid = GlobalId {
-            instance,
-            promoted: None,
-        };
-        let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id);
-        let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP);
-        Self::is_value_unfrozen_raw(cx, result, ty)
-    }
-
-    fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-        let args = cx.typeck_results().node_args(hir_id);
-
-        let result = Self::const_eval_resolve(
-            cx.tcx,
-            cx.typing_env(),
-            ty::UnevaluatedConst::new(def_id, args),
-            DUMMY_SP,
-        );
-        Self::is_value_unfrozen_raw(cx, result, ty)
+            IsFreeze::Maybe | IsFreeze::No => Ok(false),
+        }
     }
 
-    pub fn const_eval_resolve(
+    /// Checks if the given expression creates a value which is `Freeze`.
+    ///
+    /// This will return `true` if the type is maybe `Freeze`, but it cannot be
+    /// determined for certain from the value.
+    ///
+    /// `typing_env` and `gen_args` are from the constant's use site.
+    /// `typeck` and `e` are from the constant's definition site.
+    fn is_init_expr_freeze(
+        &mut self,
         tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-        ct: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) {
-            Ok(Some(instance)) => {
-                let cid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        gen_args: GenericArgsRef<'tcx>,
+        e: &'tcx Expr<'tcx>,
+    ) -> bool {
+        // Make sure to instantiate all types coming from `typeck` with `gen_args`.
+        let ty = EarlyBinder::bind(typeck.expr_ty(e)).instantiate(tcx, gen_args);
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => true,
+            IsFreeze::No => false,
+            IsFreeze::Maybe => match e.kind {
+                ExprKind::Block(b, _)
+                    if !b.targeted_by_break
+                        && b.stmts.is_empty()
+                        && let Some(e) = b.expr =>
+                {
+                    self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)
+                },
+                ExprKind::Path(ref p) => {
+                    let res = typeck.qpath_res(p, e.hir_id);
+                    let gen_args = EarlyBinder::bind(typeck.node_args(e.hir_id)).instantiate(tcx, gen_args);
+                    match res {
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Ok(val) =
+                                tcx.const_eval_resolve(typing_env, UnevaluatedConst::new(did, gen_args), DUMMY_SP)
+                                && let Ok(is_freeze) = self.is_value_freeze(tcx, typing_env, ty, val) =>
+                        {
+                            is_freeze
+                        },
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Some((typeck, init)) = get_const_hir_value(tcx, typing_env, did, gen_args) =>
+                        {
+                            self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, init)
+                        },
+                        // Either this is a unit constructor, or some unknown value.
+                        // In either case we consider the value to be `Freeze`.
+                        _ => true,
+                    }
+                },
+                ExprKind::Call(callee, args)
+                    if let ExprKind::Path(p) = &callee.kind
+                        && let res = typeck.qpath_res(p, callee.hir_id)
+                        && matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)) =>
+                {
+                    args.iter()
+                        .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e))
+                },
+                ExprKind::Struct(_, fields, StructTailExpr::None) => fields
+                    .iter()
+                    .all(|f| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, f.expr)),
+                ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs
+                    .iter()
+                    .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)),
+                ExprKind::Repeat(e, _) => self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e),
+                _ => true,
             },
-            Ok(None) => Err(ErrorHandled::TooGeneric(span)),
-            Err(err) => Err(ErrorHandled::Reported(
-                ReportedErrorInfo::non_const_eval_error(err),
-                span,
-            )),
         }
     }
-}
 
-impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
-        if let ItemKind::Const(.., body_id) = it.kind {
-            let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
-            if !ignored_macro(cx, it)
-                && self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_poly(cx, body_id, ty)
-            {
-                lint(cx, Source::Item { item: it.span, ty });
+    /// Checks if the given expression (or a local projection of it) is both borrowed and
+    /// definitely a non-`Freeze` type.
+    fn is_non_freeze_expr_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            let ty = typeck.expr_ty(src_expr);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            let is_freeze = self.is_ty_freeze(tcx, typing_env, ty);
+            if is_freeze.is_freeze() {
+                return None;
             }
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind {
-            let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity();
-
-            // Normalize assoc types because ones originated from generic params
-            // bounded other traits could have their bound.
-            let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-            if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                // When there's no default value, lint it only according to its type;
-                // in other words, lint consts whose value *could* be unfrozen, not definitely is.
-                // This feels inconsistent with how the lint treats generic types,
-                // which avoids linting types which potentially become unfrozen.
-                // One could check whether an unfrozen type have a *frozen variant*
-                // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`),
-                // and do the same as the case of generic types at impl items.
-                // Note that it isn't sufficient to check if it has an enum
-                // since all of that enum's variants can be unfrozen:
-                // i.e. having an enum doesn't necessary mean a type has a frozen variant.
-                // And, implementing it isn't a trivial task; it'll probably end up
-                // re-implementing the trait predicate evaluation specific to `Freeze`.
-                && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized))
-            {
-                lint(cx, Source::Assoc { item: trait_item.span });
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| is_freeze.is_not_freeze())
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
+            }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            match use_expr.kind {
+                ExprKind::Field(..) => {},
+                ExprKind::Index(..) if ty.is_array() => {},
+                ExprKind::AddrOf(..) if is_freeze.is_not_freeze() => {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
             }
+            src_expr = use_expr;
         }
     }
 
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if let ImplItemKind::Const(_, body_id) = &impl_item.kind {
-            let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
-            let item = cx.tcx.hir_expect_item(item_def_id);
-
-            match &item.kind {
-                ItemKind::Impl(Impl {
-                    of_trait: Some(of_trait_ref),
-                    ..
-                }) => {
-                    if let Some(of_trait_def_id) = of_trait_ref.trait_def_id()
-                        // Lint a trait impl item only when the definition is a generic type,
-                        // assuming an assoc const is not meant to be an interior mutable type.
-                        && let Some(of_assoc_item) = cx
-                            .tcx
-                            .associated_item(impl_item.owner_id)
-                            .trait_item_def_id
-                        && cx
-                            .tcx
-                            .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input(
-                                // Normalize assoc types because ones originated from generic params
-                                // bounded other traits could have their bound at the trait defs;
-                                // and, in that case, the definition is *not* generic.
-                                cx.tcx.normalize_erasing_regions(
-                                    ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id),
-                                    cx.tcx.type_of(of_assoc_item).instantiate_identity(),
-                                ),
-                            ))
-                            .is_err()
-                            // If there were a function like `has_frozen_variant` described above,
-                            // we should use here as a frozen variant is a potential to be frozen
-                            // similar to unknown layouts.
-                            // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
-                        && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
-                        && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty)
-                        && self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`. Returns `Err` if the constant cannot be read, but the
+    /// result depends on the value.
+    fn is_non_freeze_val_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut val: ConstValue<'tcx>,
+    ) -> Result<Option<BorrowSource<'tcx>>, ()> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        let mut ty = typeck.expr_ty(src_expr);
+        loop {
+            // Normalized as we need to check if this is an array later.
+            ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                let res = if let Some(cause) = does_adjust_borrow(adjust)
+                    && !self.is_value_freeze(tcx, typing_env, ty, val)?
+                {
+                    Some(BorrowSource::new(tcx, src_expr, cause))
+                } else {
+                    None
+                };
+                return Ok(res);
+            }
+            // Check only the type here as the result gets cached for each type.
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return Ok(None);
+            }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return Ok(None);
+            };
+            let next_val = match use_expr.kind {
+                ExprKind::Field(_, name) => {
+                    if let Some(idx) = get_field_idx_by_name(ty, name.name) {
+                        tcx.try_destructure_mir_constant_for_user_output(val, ty)
+                            .ok_or(())?
+                            .fields
+                            .get(idx)
+                    } else {
+                        return Ok(None);
                     }
                 },
-                ItemKind::Impl(Impl { of_trait: None, .. }) => {
-                    let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
-                    // Normalize assoc types originated from generic params.
-                    let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-
-                    if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+                ExprKind::Index(_, idx, _) if ty.is_array() => {
+                    let val = tcx.try_destructure_mir_constant_for_user_output(val, ty).ok_or(())?;
+                    if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                        val.fields.get(idx as usize)
+                    } else {
+                        // It's some value in the array so check all of them.
+                        for &(val, _) in val.fields {
+                            if let Some(src) =
+                                self.is_non_freeze_val_borrowed(tcx, typing_env, typeck, use_expr, val)?
+                            {
+                                return Ok(Some(src));
+                            }
+                        }
+                        return Ok(None);
                     }
                 },
-                _ => (),
+                ExprKind::AddrOf(..) if !self.is_value_freeze(tcx, typing_env, ty, val)? => {
+                    return Ok(Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)));
+                },
+                // All other expressions use the value.
+                _ => return Ok(None),
+            };
+            src_expr = use_expr;
+            if let Some(&(next_val, next_ty)) = next_val {
+                ty = next_ty;
+                val = next_val;
+            } else {
+                return Ok(None);
             }
         }
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Path(qpath) = &expr.kind {
-            // Only lint if we use the const item inside a function.
-            if is_in_const_context(cx) {
-                return;
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`.
+    ///
+    /// `typing_env` and `init_args` are from the constant's use site.
+    /// `init_typeck` and `init_expr` are from the constant's definition site.
+    #[expect(clippy::too_many_arguments, clippy::too_many_lines)]
+    fn is_non_freeze_init_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut init_typeck: &'tcx TypeckResults<'tcx>,
+        mut init_args: GenericArgsRef<'tcx>,
+        mut init_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        // Make sure to instantiate all types coming from `init_typeck` with `init_args`.
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            // First handle any adjustments since they are cheap to check.
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr))
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
             }
 
-            // Make sure it is a const item.
-            let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
-                return;
-            };
-
-            // Climb up to resolve any field access and explicit referencing.
-            let mut cur_expr = expr;
-            let mut dereferenced_expr = expr;
-            let mut needs_check_adjustment = true;
+            // Then read through constants and blocks on the init expression before
+            // applying the next use expression.
             loop {
-                let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id);
-                if parent_id == cur_expr.hir_id {
-                    break;
+                match init_expr.kind {
+                    ExprKind::Block(b, _)
+                        if !b.targeted_by_break
+                            && b.stmts.is_empty()
+                            && let Some(next_init) = b.expr =>
+                    {
+                        init_expr = next_init;
+                    },
+                    ExprKind::Path(ref init_path) => {
+                        let next_init_args =
+                            EarlyBinder::bind(init_typeck.node_args(init_expr.hir_id)).instantiate(tcx, init_args);
+                        match init_typeck.qpath_res(init_path, init_expr.hir_id) {
+                            Res::Def(DefKind::Ctor(..), _) => return None,
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Ok(val) = tcx.const_eval_resolve(
+                                    typing_env,
+                                    UnevaluatedConst::new(did, next_init_args),
+                                    DUMMY_SP,
+                                ) && let Ok(res) =
+                                    self.is_non_freeze_val_borrowed(tcx, typing_env, init_typeck, src_expr, val) =>
+                            {
+                                return res;
+                            },
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Some((next_typeck, value)) =
+                                    get_const_hir_value(tcx, typing_env, did, next_init_args) =>
+                            {
+                                init_typeck = next_typeck;
+                                init_args = next_init_args;
+                                init_expr = value;
+                            },
+                            // There's no more that we can read from the init expression. Switch to a
+                            // type based check.
+                            _ => {
+                                return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, src_expr);
+                            },
+                        }
+                    },
+                    _ => break,
                 }
-                if let Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) {
-                    match &parent_expr.kind {
-                        ExprKind::AddrOf(..) => {
-                            // `&e` => `e` must be referenced.
-                            needs_check_adjustment = false;
-                        },
-                        ExprKind::Field(..) => {
-                            needs_check_adjustment = true;
+            }
 
-                            // Check whether implicit dereferences happened;
-                            // if so, no need to go further up
-                            // because of the same reason as the `ExprKind::Unary` case.
-                            if cx
-                                .typeck_results()
-                                .expr_adjustments(dereferenced_expr)
-                                .iter()
-                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                            {
-                                break;
-                            }
+            // Then a type check. Note we only check the type here as the result
+            // gets cached.
+            let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return None;
+            }
 
-                            dereferenced_expr = parent_expr;
-                        },
-                        ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => {
-                            // `e[i]` => desugared to `*Index::index(&e, i)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
-                        },
-                        ExprKind::Unary(UnOp::Deref, _) => {
-                            // `*e` => desugared to `*Deref::deref(&e)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
+            // Finally reduce the init expression using the next use expression.
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            init_expr = match &use_expr.kind {
+                ExprKind::Field(_, name) => match init_expr.kind {
+                    ExprKind::Struct(_, fields, _)
+                        if let Some(field) = fields.iter().find(|f| f.ident.name == name.name) =>
+                    {
+                        field.expr
+                    },
+                    ExprKind::Tup(fields)
+                        if let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(field) = fields.get(idx) =>
+                    {
+                        field
+                    },
+                    ExprKind::Call(callee, args)
+                        if let ExprKind::Path(callee_path) = &callee.kind
+                            && matches!(
+                                init_typeck.qpath_res(callee_path, callee.hir_id),
+                                Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)
+                            )
+                            && let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(arg) = args.get(idx) =>
+                    {
+                        arg
+                    },
+                    // Revert to a type based check as we don't know the field's value.
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::Index(_, idx, _) if ty.is_array() => match init_expr.kind {
+                    ExprKind::Array(fields) => {
+                        if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                            // If the index is out of bounds it means the code
+                            // unconditionally panics. In that case there is no borrow.
+                            fields.get(idx as usize)?
+                        } else {
+                            // Unknown index, just run the check for all values.
+                            return fields.iter().find_map(|f| {
+                                self.is_non_freeze_init_borrowed(
+                                    tcx,
+                                    typing_env,
+                                    typeck,
+                                    use_expr,
+                                    init_typeck,
+                                    init_args,
+                                    f,
+                                )
+                            });
+                        }
+                    },
+                    // Just assume the index expression doesn't panic here.
+                    ExprKind::Repeat(field, _) => field,
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::AddrOf(..)
+                    if !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr) =>
+                {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
+            };
+            src_expr = use_expr;
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if let ItemKind::Const(ident, .., body_id) = item.kind
+            && !ident.is_special()
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Yes => false,
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+            // Only needed when compiling `std`
+            && !is_thread_local(cx, item)
+        {
+            span_lint_and_then(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                ident.span,
+                "named constant with interior mutability",
+                |diag| {
+                    let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
+                        return;
+                    };
+                    if implements_trait(cx, ty, sync_trait, &[]) {
+                        diag.help("did you mean to make this a `static` item");
+                    } else {
+                        diag.help("did you mean to make this a `thread_local!` item");
+                    }
+                },
+            );
+        }
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        if let TraitItemKind::Const(_, body_id_opt) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Maybe if let Some(body_id) = body_id_opt => {
+                    match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                        Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => {
+                            !is_freeze
                         },
-                        _ => break,
+                        _ => !self.is_init_expr_freeze(
+                            cx.tcx,
+                            cx.typing_env(),
+                            cx.tcx.typeck(item.owner_id),
+                            GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                            cx.tcx.hir_body(body_id).value,
+                        ),
                     }
-                    cur_expr = parent_expr;
-                } else {
-                    break;
-                }
+                },
+                IsFreeze::Yes | IsFreeze::Maybe => false,
             }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "named constant with interior mutability",
+            );
+        }
+    }
 
-            let ty = if needs_check_adjustment {
-                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
-                if let Some(i) = adjustments
-                    .iter()
-                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
-                {
-                    if i == 0 {
-                        cx.typeck_results().expr_ty(dereferenced_expr)
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
+        if let ImplItemKind::Const(_, body_id) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::Yes => false,
+                IsFreeze::No => {
+                    // If this is a trait impl, check if the trait definition is the source
+                    // of the cell.
+                    if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
+                        && let ItemKind::Impl(impl_block) = parent_item.kind
+                        && let Some(of_trait) = impl_block.of_trait
+                        && let Some(trait_id) = of_trait.trait_def_id()
+                    {
+                        // Replace all instances of `<Self as Trait>::AssocType` with the
+                        // unit type and check again. If the result is the same then the
+                        // trait definition is the cause.
+                        let ty = (ReplaceAssocFolder {
+                            tcx: cx.tcx,
+                            trait_id,
+                            self_ty: cx.tcx.type_of(parent_item.owner_id).instantiate_identity(),
+                        })
+                        .fold_ty(cx.tcx.type_of(item.owner_id).instantiate_identity());
+                        // `ty` may not be normalizable, but that should be fine.
+                        !self.is_ty_freeze(cx.tcx, cx.typing_env(), ty).is_not_freeze()
                     } else {
-                        adjustments[i - 1].target
+                        true
                     }
+                },
+                // Even if this is from a trait, there are values which don't have
+                // interior mutability.
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "named constant with interior mutability",
+            );
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Path(qpath) = &e.kind
+            && let typeck = cx.typeck_results()
+            && let Res::Def(DefKind::Const | DefKind::AssocConst, did) = typeck.qpath_res(qpath, e.hir_id)
+            // As of `1.80` constant contexts can't borrow any type with interior mutability
+            && !is_in_const_context(cx)
+            && !self.is_ty_freeze(cx.tcx, cx.typing_env(), typeck.expr_ty(e)).is_freeze()
+            && let Some(borrow_src) = {
+                // The extra block helps formatting a lot.
+                if let Ok(val) = cx.tcx.const_eval_resolve(
+                    cx.typing_env(),
+                    UnevaluatedConst::new(did, typeck.node_args(e.hir_id)),
+                    DUMMY_SP,
+                ) && let Ok(src) = self.is_non_freeze_val_borrowed(cx.tcx, cx.typing_env(), typeck, e, val)
+                {
+                    src
+                } else if let init_args = typeck.node_args(e.hir_id)
+                    && let Some((init_typeck, init)) = get_const_hir_value(cx.tcx, cx.typing_env(), did, init_args)
+                {
+                    self.is_non_freeze_init_borrowed(cx.tcx, cx.typing_env(), typeck, e, init_typeck, init_args, init)
                 } else {
-                    // No borrow adjustments means the entire const is moved.
-                    return;
+                    self.is_non_freeze_expr_borrowed(cx.tcx, cx.typing_env(), typeck, e)
                 }
-            } else {
-                cx.typeck_results().expr_ty(dereferenced_expr)
-            };
-
-            if self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
-            {
-                lint(cx, Source::Expr { expr: expr.span });
             }
+            && !borrow_src.expr.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint_and_then(
+                cx,
+                BORROW_INTERIOR_MUTABLE_CONST,
+                borrow_src.expr.span,
+                "borrow of a named constant with interior mutability",
+                |diag| {
+                    if let Some(note) = borrow_src.cause.note() {
+                        diag.note(note);
+                    }
+                    diag.help("this lint can be silenced by assigning the value to a local variable before borrowing");
+                },
+            );
+        }
+    }
+}
+
+struct ReplaceAssocFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    trait_id: DefId,
+    self_ty: Ty<'tcx>,
+}
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAssocFolder<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind()
+            && ty.trait_def_id(self.tcx) == self.trait_id
+            && ty.self_ty() == self.self_ty
+        {
+            self.tcx.types.unit
+        } else {
+            ty.super_fold_with(self)
         }
     }
 }
 
-fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
+fn is_thread_local(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
     macro_backtrace(it.span).any(|macro_call| {
         matches!(
             cx.tcx.get_diagnostic_name(macro_call.def_id),
@@ -507,3 +891,42 @@ fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
         )
     })
 }
+
+/// Checks if the adjustment causes a borrow of the original value. Returns
+/// `None` if the value is consumed instead of borrowed.
+fn does_adjust_borrow(adjust: &Adjustment<'_>) -> Option<BorrowCause> {
+    match adjust.kind {
+        Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow),
+        // Custom deref calls `<T as Deref>::deref(&x)` resulting in a borrow.
+        Adjust::Deref(Some(_)) => Some(BorrowCause::AutoDeref),
+        // All other adjustments read the value.
+        _ => None,
+    }
+}
+
+/// Attempts to get the value of a constant as a HIR expression. Also gets the
+/// `TypeckResults` associated with the constant's body.
+fn get_const_hir_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: TypingEnv<'tcx>,
+    did: DefId,
+    args: GenericArgsRef<'tcx>,
+) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> {
+    let did = did.as_local()?;
+    let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+        Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::TraitItem(_)
+            if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args)
+                && let Some(did) = inst.def_id().as_local() =>
+        {
+            match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+                Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+                Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id),
+                _ => return None,
+            }
+        },
+        _ => return None,
+    };
+    Some((tcx.typeck(did), tcx.hir_body(body_id).value))
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 03b907ebdf4..4be42267b14 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
             let rty = cx.typeck_results().expr_ty(rhs);
             if let Some((_, lang_item)) = binop_traits(op.node)
                 && let Some(trait_id) = cx.tcx.lang_items().get(lang_item)
-                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id).def_id
+                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id)
                 && trait_ref_of_method(cx, parent_fn).is_none_or(|t| t.path.res.def_id() != trait_id)
                 && implements_trait(cx, ty, trait_id, &[rty.into()])
             {
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index e3029f8438e..6c9be7c5e90 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -1,11 +1,11 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_span::sym;
 
 use super::DURATION_SUBSEC;
 
@@ -21,9 +21,9 @@ pub(crate) fn check<'tcx>(
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
         && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
     {
-        let suggested_fn = match (method_path.ident.as_str(), divisor) {
-            ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
-            ("subsec_nanos", 1_000) => "subsec_micros",
+        let suggested_fn = match (method_path.ident.name, divisor) {
+            (sym::subsec_micros, 1_000) | (sym::subsec_nanos, 1_000_000) => "subsec_millis",
+            (sym::subsec_nanos, 1_000) => "subsec_micros",
             _ => return,
         };
         let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index d16f5f8e112..64ad92b1ebb 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -37,7 +37,7 @@ impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
             && matches!(seg.ident.name, sym::expect | sym::unwrap)
-            && is_direct_expn_of(receiver.span, "option_env").is_some()
+            && is_direct_expn_of(receiver.span, sym::option_env).is_some()
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 122d97fdf81..ab9b0f88f93 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -423,7 +423,14 @@ fn check_final_expr<'tcx>(
                 _ => return,
             }
 
-            emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
+            emit_return_lint(
+                cx,
+                peeled_drop_expr.span,
+                ret_span,
+                semi_spans,
+                &replacement,
+                expr.hir_id,
+            );
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
@@ -448,6 +455,7 @@ fn check_final_expr<'tcx>(
 
 fn emit_return_lint(
     cx: &LateContext<'_>,
+    lint_span: Span,
     ret_span: Span,
     semi_spans: Vec<Span>,
     replacement: &RetReplacement<'_>,
@@ -457,7 +465,7 @@ fn emit_return_lint(
         cx,
         NEEDLESS_RETURN,
         at,
-        ret_span,
+        lint_span,
         "unneeded `return` statement",
         |diag| {
             let suggestions = std::iter::once((ret_span, replacement.to_string()))
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index ccb1209c6fc..f3fea3add59 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{GenericArgKind, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Ident;
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::{DUMMY_SP, Span};
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -169,7 +169,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
             let mut iter = get_attr(
                 self.cx.sess(),
                 self.cx.tcx.get_attrs_unchecked(adt.did()),
-                "has_significant_drop",
+                sym::has_significant_drop,
             );
             if iter.next().is_some() {
                 return true;
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index 835ec1e4ca1..3623039aece 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::sym;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -62,17 +63,17 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
-    const METHODS: [&str; 10] = [
-        "copy_to",
-        "copy_from",
-        "copy_to_nonoverlapping",
-        "copy_from_nonoverlapping",
-        "add",
-        "wrapping_add",
-        "sub",
-        "wrapping_sub",
-        "offset",
-        "wrapping_offset",
+    const METHODS: [Symbol; 10] = [
+        sym::copy_to,
+        sym::copy_from,
+        sym::copy_to_nonoverlapping,
+        sym::copy_from_nonoverlapping,
+        sym::add,
+        sym::wrapping_add,
+        sym::sub,
+        sym::wrapping_sub,
+        sym::offset,
+        sym::wrapping_offset,
     ];
 
     if let ExprKind::Call(func, [.., count]) = expr.kind
@@ -97,7 +98,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     }
     if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
         // Find calls to copy_{from,to}{,_nonoverlapping}
-        && let method_ident = method_path.ident.as_str()
+        && let method_ident = method_path.ident.name
         && METHODS.contains(&method_ident)
 
         // Get the pointee type
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 30a5fe4db27..f497d0700b8 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -266,7 +266,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
             let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
                 // If we have a size expression, check that it is equal to what's passed to `resize`
                 SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
-                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity)
             } else {
                 self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
                 true
@@ -288,7 +288,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
             if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
                 // Check that len expression is equals to `with_capacity` expression
                 return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
-                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity");
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity);
             }
 
             self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index d68ac8bab12..3d39386ecf9 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::Msrv;
-use rustc_attr_parsing::{StabilityLevel, StableSince};
+use rustc_attr_data_structures::{StabilityLevel, StableSince};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index 5c95dfe8347..f63e6b3087b 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -5,9 +5,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::path_to_local_id;
 use clippy_utils::source::{snippet, str_literal_to_char_literal};
 use clippy_utils::visitors::{Descend, for_each_expr};
+use clippy_utils::{path_to_local_id, sym};
 use itertools::Itertools;
 use rustc_ast::{BinOpKind, LitKind};
 use rustc_errors::Applicability;
@@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -83,29 +83,29 @@ impl StringPatterns {
 
 impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]);
 
-const PATTERN_METHODS: [(&str, usize); 22] = [
-    ("contains", 0),
-    ("starts_with", 0),
-    ("ends_with", 0),
-    ("find", 0),
-    ("rfind", 0),
-    ("split", 0),
-    ("split_inclusive", 0),
-    ("rsplit", 0),
-    ("split_terminator", 0),
-    ("rsplit_terminator", 0),
-    ("splitn", 1),
-    ("rsplitn", 1),
-    ("split_once", 0),
-    ("rsplit_once", 0),
-    ("matches", 0),
-    ("rmatches", 0),
-    ("match_indices", 0),
-    ("rmatch_indices", 0),
-    ("trim_start_matches", 0),
-    ("trim_end_matches", 0),
-    ("replace", 0),
-    ("replacen", 0),
+const PATTERN_METHODS: [(Symbol, usize); 22] = [
+    (sym::contains, 0),
+    (sym::starts_with, 0),
+    (sym::ends_with, 0),
+    (sym::find, 0),
+    (sym::rfind, 0),
+    (sym::split, 0),
+    (sym::split_inclusive, 0),
+    (sym::rsplit, 0),
+    (sym::split_terminator, 0),
+    (sym::rsplit_terminator, 0),
+    (sym::splitn, 1),
+    (sym::rsplitn, 1),
+    (sym::split_once, 0),
+    (sym::rsplit_once, 0),
+    (sym::matches, 0),
+    (sym::rmatches, 0),
+    (sym::match_indices, 0),
+    (sym::rmatch_indices, 0),
+    (sym::trim_start_matches, 0),
+    (sym::trim_end_matches, 0),
+    (sym::replace, 0),
+    (sym::replacen, 0),
 ];
 
 fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) {
@@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns {
             && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind
             && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind()
             && ty.is_str()
-            && let method_name = method.ident.name.as_str()
+            && let method_name = method.ident.name
             && let Some(&(_, pos)) = PATTERN_METHODS
                 .iter()
                 .find(|(array_method_name, _)| *array_method_name == method_name)
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 1ada7094dc5..33856c750d7 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::match_libc_symbol;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
+use clippy_utils::{match_libc_symbol, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
             && let ExprKind::Call(func, [recv]) = expr.kind
             && let ExprKind::Path(path) = &func.kind
             && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id()
-            && match_libc_symbol(cx, did, "strlen")
+            && match_libc_symbol(cx, did, sym::strlen)
             && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind
             && !recv.span.from_expansion()
             && path.ident.name == sym::as_ptr
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 83241f97a99..edb7600b7c0 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -80,7 +80,7 @@ fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, bin
             && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn)
             && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind
             && let body = cx.tcx.hir_body(body_id)
-            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id).def_id
+            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id)
             && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
             && let trait_id = trait_ref.path.res.def_id()
             && ![binop_trait_id, op_assign_trait_id].contains(&trait_id)
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index bcd05cceca9..54a7efc090a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
@@ -78,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
         fn_kind: FnKind<'tcx>,
         fn_decl: &FnDecl<'tcx>,
         body: &Body<'tcx>,
-        span: Span,
+        _span: Span,
         def_id: LocalDefId,
     ) {
         // Abort if public function/method or closure.
@@ -147,19 +149,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
                     "remove the return type...".to_string(),
                     // FIXME: we should instead get the span including the `->` and suggest an
                     // empty string for this case.
-                    "()".to_string(),
-                    "...and then remove returned values",
+                    Cow::Borrowed("()"),
+                    Cow::Borrowed("...and then remove returned values"),
                 )
             } else {
+                let wrapper = if lang_item == OptionSome { "Some" } else { "Ok" };
                 (
                     format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"),
                     format!("remove `{return_type_label}` from the return type..."),
-                    inner_type.to_string(),
-                    "...and then change returning expressions",
+                    Cow::Owned(inner_type.to_string()),
+                    Cow::Owned(format!(
+                        "...and then remove the surrounding `{wrapper}()` from returning expressions"
+                    )),
                 )
             };
 
-            span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| {
+            span_lint_and_then(cx, UNNECESSARY_WRAPS, cx.tcx.def_span(def_id), lint_msg, |diag| {
                 diag.span_suggestion(
                     fn_decl.output.span(),
                     return_type_sugg_msg,
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 7487e273caa..1f5351e32aa 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
-use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::ops::ControlFlow;
 
 declare_clippy_lint! {
@@ -150,10 +149,10 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                 remaining_args,
                                 _,
                             ) => {
-                                let method_name = method_name_ident.name.as_str();
+                                let method_name = method_name_ident.name;
 
                                 // `Peekable` methods
-                                if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
+                                if matches!(method_name, sym::peek | sym::peek_mut | sym::next_if | sym::next_if_eq)
                                     && arg_is_mut_peekable(self.cx, self_arg)
                                 {
                                     return ControlFlow::Break(());
@@ -167,7 +166,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                 }
 
                                 // foo.by_ref(), keep checking for `peek`
-                                if method_name == "by_ref" {
+                                if method_name == sym::by_ref {
                                     continue;
                                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 3e5afec541c..c21004b5362 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -1,9 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
+use clippy_utils::sym;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -30,19 +32,20 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
 
-fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
+fn is_useless_rounding(cx: &EarlyContext<'_>, expr: &Expr) -> Option<(Symbol, String)> {
     if let ExprKind::MethodCall(box MethodCall {
         seg: name_ident,
         receiver,
         ..
     }) = &expr.kind
-        && let method_name = name_ident.ident.name.as_str()
-        && (method_name == "ceil" || method_name == "round" || method_name == "floor")
+        && let method_name = name_ident.ident.name
+        && matches!(method_name, sym::ceil | sym::floor | sym::round)
         && let ExprKind::Lit(token_lit) = &receiver.kind
         && token_lit.is_semantic_float()
         && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>()
+        && f.fract() == 0.0
     {
-        (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string()))
+        Some((method_name, snippet(cx, receiver.span, "..").into()))
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index f870eb71e19..7bec212a23c 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -79,7 +79,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
         let mut result = Vec::new();
         let _: Option<!> = for_each_expr(cx, body.value, |e| {
             // check for `expect`
-            if let Some(arglists) = method_chain_args(e, &["expect"]) {
+            if let Some(arglists) = method_chain_args(e, &[sym::expect]) {
                 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
@@ -89,7 +89,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
             }
 
             // check for `unwrap`
-            if let Some(arglists) = method_chain_args(e, &["unwrap"]) {
+            if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) {
                 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
diff --git a/src/tools/clippy/clippy_lints/src/useless_concat.rs b/src/tools/clippy/clippy_lints/src/useless_concat.rs
new file mode 100644
index 00000000000..1ed1fbb3b9c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/useless_concat.rs
@@ -0,0 +1,104 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::macros::macro_backtrace;
+use clippy_utils::paths::CONCAT;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::tokenize_with_text;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lexer::TokenKind;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks that the `concat!` macro has at least two arguments.
+    ///
+    /// ### Why is this bad?
+    /// If there are less than 2 arguments, then calling the macro is doing nothing.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = concat!("a");
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = "a";
+    /// ```
+    #[clippy::version = "1.89.0"]
+    pub USELESS_CONCAT,
+    complexity,
+    "checks that the `concat` macro has at least two arguments"
+}
+
+declare_lint_pass!(UselessConcat => [USELESS_CONCAT]);
+
+impl LateLintPass<'_> for UselessConcat {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        // Check that the expression is generated by a macro.
+        if expr.span.from_expansion()
+            // Check that it's a string literal.
+            && let ExprKind::Lit(lit) = expr.kind
+            && let LitKind::Str(lit_s, _) = lit.node
+            // Get the direct parent of the expression.
+            && let Some(macro_call) = macro_backtrace(expr.span).next()
+            // Check if the `concat` macro from the `core` library.
+            && CONCAT.matches(cx, macro_call.def_id)
+            // We get the original code to parse it.
+            && let Some(original_code) = snippet_opt(cx, macro_call.span)
+            // This check allows us to ensure that the code snippet:
+            // 1. Doesn't come from proc-macro expansion.
+            // 2. Doesn't come from foreign macro expansion.
+            //
+            // It works as follows: if the snippet we get doesn't contain `concat!(`, then it
+            // means it's not code written in the current crate so we shouldn't lint.
+            && let mut parts = original_code.split('!')
+            && parts.next().is_some_and(|p| p.trim() == "concat")
+            && parts.next().is_some_and(|p| p.trim().starts_with('('))
+        {
+            let mut literal = None;
+            let mut nb_commas = 0;
+            let mut nb_idents = 0;
+            for (token_kind, token_s, _) in tokenize_with_text(&original_code) {
+                match token_kind {
+                    TokenKind::Eof => break,
+                    TokenKind::Literal { .. } => {
+                        if literal.is_some() {
+                            return;
+                        }
+                        literal = Some(token_s);
+                    },
+                    TokenKind::Ident => {
+                        if token_s == "true" || token_s == "false" {
+                            literal = Some(token_s);
+                        } else {
+                            nb_idents += 1;
+                        }
+                    },
+                    TokenKind::Comma => {
+                        nb_commas += 1;
+                        if nb_commas > 1 {
+                            return;
+                        }
+                    },
+                    // We're inside a macro definition and we are manipulating something we likely
+                    // shouldn't, so aborting.
+                    TokenKind::Dollar => return,
+                    _ => {},
+                }
+            }
+            // There should always be the ident of the `concat` macro.
+            if nb_idents == 1 {
+                span_lint_and_sugg(
+                    cx,
+                    USELESS_CONCAT,
+                    macro_call.span,
+                    "unneeded use of `concat!` macro",
+                    "replace with",
+                    format!("{lit_s:?}"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 3a9c997a579..380ddea4e1e 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -3,11 +3,11 @@ use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::{DiagExt as _, Sugg};
 use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{
-    get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local,
+    get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
+use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::Obligation;
 use rustc_lint::{LateContext, LateLintPass};
@@ -15,7 +15,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 
 declare_clippy_lint! {
@@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
             },
 
             ExprKind::MethodCall(name, recv, [], _) => {
-                if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
+                if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
@@ -298,6 +298,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     // implements Copy, in which case .into_iter() returns a copy of the receiver and
                     // cannot be safely omitted.
                     if same_type_and_consts(a, b) && !is_copy(cx, b) {
+                        // Below we check if the parent method call meets the following conditions:
+                        // 1. First parameter is `&mut self` (requires mutable reference)
+                        // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
+                        // For methods satisfying these conditions (like any), .into_iter() must be preserved.
+                        if let Some(parent) = get_parent_expr(cx, e)
+                            && let ExprKind::MethodCall(_, recv, _, _) = parent.kind
+                            && recv.hir_id == e.hir_id
+                            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
+                            && let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder()
+                            && let inputs = sig.inputs()
+                            && inputs.len() >= 2
+                            && let Some(self_ty) = inputs.first()
+                            && let ty::Ref(_, _, Mutability::Mut) = self_ty.kind()
+                            && let Some(second_ty) = inputs.get(1)
+                            && let predicates = cx.tcx.param_env(def_id).caller_bounds()
+                            && predicates.iter().any(|pred| {
+                                if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
+                                    trait_pred.self_ty() == *second_ty
+                                        && cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id())
+                                } else {
+                                    false
+                                }
+                            })
+                        {
+                            return;
+                        }
+
                         let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 812c4df4ddd..3a08531cf1c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{MaybePath, get_attr, higher, path_def_id};
+use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym};
 use itertools::Itertools;
 use rustc_ast::LitIntType;
 use rustc_ast::ast::{LitFloatType, LitKind};
@@ -826,5 +826,5 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
 fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let attrs = cx.tcx.hir_attrs(hir_id);
-    get_attr(cx.sess(), attrs, "author").count() > 0
+    get_attr(cx.sess(), attrs, sym::author).count() > 0
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
index 9910be9bc28..d6cf07fdaf3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
@@ -1,4 +1,4 @@
-use clippy_utils::get_attr;
+use clippy_utils::{get_attr, sym};
 use hir::TraitItem;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -60,5 +60,5 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir {
 
 fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
     let attrs = cx.tcx.hir_attrs(hir_id);
-    get_attr(cx.sess(), attrs, "dump").count() > 0
+    get_attr(cx.sess(), attrs, sym::dump).count() > 0
 }
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 3346b15dae9..7b6a25123e8 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -8,14 +8,14 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_session::impl_lint_pass;
-use rustc_span::{DesugaringKind, Span, sym};
+use rustc_span::{DesugaringKind, Span};
 
 pub struct UselessVec {
     too_large_for_stack: u64,
@@ -249,10 +249,8 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// that also exists on slices. If this returns true, it means that
 /// this expression does not actually require a `Vec` and could just work with an array.
 pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
-
     if let ExprKind::MethodCall(path, _, [], _) = e.kind {
-        ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str())
+        matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
     } else {
         is_trait_method(cx, e, sym::IntoIterator)
     }
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 24b1381ba45..1550872bca2 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -51,9 +51,11 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
             && let ty::Adt(_, args) = ty.kind()
             && let ty = args.type_at(1)
-            // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of
-            // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968
-            && !ty.has_escaping_bound_vars()
+            // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case.
+            // This might happen when computing a reference/pointer metadata on a type for which we
+            // cannot check if it is `Sized` or not, such as an incomplete associated type in a
+            // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`.
+            && !ty.has_non_region_param()
             && let Ok(layout) = cx.layout_of(ty)
             && layout.is_zst()
         {
diff --git a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
index 4fd5ea459a5..311f76fee6b 100644
--- a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
@@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use regex::Regex;
 use rustc_hir::{Attribute, Item, ItemKind, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_tool_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
index 407deb45db0..7c9e7286925 100644
--- a/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
@@ -4,8 +4,7 @@ use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt};
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
 use std::borrow::{Borrow, Cow};
diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs
index 43cde86504f..0c94d100c41 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lib.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs
@@ -20,6 +20,7 @@
 #![allow(clippy::missing_clippy_version_attribute)]
 
 extern crate rustc_ast;
+extern crate rustc_attr_data_structures;
 extern crate rustc_attr_parsing;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
index 655d8fb8d1b..0edeef3ab85 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -10,9 +10,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::hir::nested_filter;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, sym};
diff --git a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
index d48d8dc57b2..441c6884852 100644
--- a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
@@ -4,9 +4,8 @@ use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::ty::{self, EarlyBinder, GenericArgKind};
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_tool_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
index 40951443a48..5cdc66ae905 100644
--- a/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
@@ -1,12 +1,11 @@
 use crate::internal_paths;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_lint_allowed, method_calls};
+use clippy_utils::{is_lint_allowed, method_calls, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_lint_defs::declare_tool_lint;
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::Symbol;
 
 declare_tool_lint! {
     /// ### What it does
@@ -40,8 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
         }
 
         let (method_names, arg_lists, spans) = method_calls(expr, 2);
-        let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
-        if let ["expn_data", "outer_expn"] = method_names.as_slice()
+        if let [sym::expn_data, sym::outer_expn] = method_names.as_slice()
             && let (self_arg, args) = arg_lists[1]
             && args.is_empty()
             && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
diff --git a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
index 14e93dc6d5f..3a813b4b9a2 100644
--- a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
@@ -1,8 +1,7 @@
 use rustc_ast::ast::NodeId;
 use rustc_ast::visit::FnKind;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
 declare_tool_lint! {
diff --git a/src/tools/clippy/clippy_lints_internal/src/symbols.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
index 5aee545fb0f..7b5d58824c3 100644
--- a/src/tools/clippy/clippy_lints_internal/src/symbols.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
@@ -6,10 +6,9 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::mir::ConstValue;
 use rustc_middle::ty;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, sym};
 
diff --git a/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
index 8e281ecb2ee..9ca4ae31d45 100644
--- a/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::sym;
 use rustc_ast::ast::{Crate, ItemKind, ModKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_tool_lint! {
     /// ### What it does
@@ -26,11 +26,11 @@ impl EarlyLintPass for UnsortedClippyUtilsPaths {
         if let Some(utils) = krate
             .items
             .iter()
-            .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils"))
+            .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::utils))
             && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind
             && let Some(paths) = items
                 .iter()
-                .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths"))
+                .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::paths))
             && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind
         {
             let mut last_name: Option<String> = None;
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index ac970e1c4b0..615c0995e8b 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_utils"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index d4080d06d3c..c9083f654c4 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-05-14
+nightly-2025-05-21
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 09de5c05537..8a0ff5323c9 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -5,11 +5,11 @@ use rustc_lexer::TokenKind;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 use std::str::FromStr;
 
 use crate::source::SpanRangeExt;
-use crate::tokenize_with_text;
+use crate::{sym, tokenize_with_text};
 
 /// Deprecation status of attributes known by Clippy.
 pub enum DeprecationStatus {
@@ -21,17 +21,17 @@ pub enum DeprecationStatus {
 }
 
 #[rustfmt::skip]
-pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
-    ("author",                DeprecationStatus::None),
-    ("version",               DeprecationStatus::None),
-    ("cognitive_complexity",  DeprecationStatus::None),
-    ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
-    ("dump",                  DeprecationStatus::None),
-    ("msrv",                  DeprecationStatus::None),
+pub const BUILTIN_ATTRIBUTES: &[(Symbol, DeprecationStatus)] = &[
+    (sym::author,                DeprecationStatus::None),
+    (sym::version,               DeprecationStatus::None),
+    (sym::cognitive_complexity,  DeprecationStatus::None),
+    (sym::cyclomatic_complexity, DeprecationStatus::Replaced("cognitive_complexity")),
+    (sym::dump,                  DeprecationStatus::None),
+    (sym::msrv,                  DeprecationStatus::None),
     // The following attributes are for the 3rd party crate authors.
     // See book/src/attribs.md
-    ("has_significant_drop",  DeprecationStatus::None),
-    ("format_args",           DeprecationStatus::None),
+    (sym::has_significant_drop,  DeprecationStatus::None),
+    (sym::format_args,           DeprecationStatus::None),
 ];
 
 pub struct LimitStack {
@@ -52,11 +52,11 @@ impl LimitStack {
     pub fn limit(&self) -> u64 {
         *self.stack.last().expect("there should always be a value in the stack")
     }
-    pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
+    pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
         let stack = &mut self.stack;
         parse_attrs(sess, attrs, name, |val| stack.push(val));
     }
-    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
+    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
         let stack = &mut self.stack;
         parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
     }
@@ -65,7 +65,7 @@ impl LimitStack {
 pub fn get_attr<'a, A: AttributeExt + 'a>(
     sess: &'a Session,
     attrs: &'a [A],
-    name: &'static str,
+    name: Symbol,
 ) -> impl Iterator<Item = &'a A> {
     attrs.iter().filter(move |attr| {
         let Some(attr_segments) = attr.ident_path() else {
@@ -75,8 +75,8 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
         if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy {
             BUILTIN_ATTRIBUTES
                 .iter()
-                .find_map(|&(builtin_name, ref deprecation_status)| {
-                    if attr_segments[1].name.as_str() == builtin_name {
+                .find_map(|(builtin_name, deprecation_status)| {
+                    if attr_segments[1].name == *builtin_name {
                         Some(deprecation_status)
                     } else {
                         None
@@ -108,7 +108,7 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
                             },
                             DeprecationStatus::None => {
                                 diag.cancel();
-                                attr_segments[1].as_str() == name
+                                attr_segments[1].name == name
                             },
                         }
                     },
@@ -119,9 +119,9 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
     })
 }
 
-fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) {
+fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: Symbol, mut f: F) {
     for attr in get_attr(sess, attrs, name) {
-        if let Some(ref value) = attr.value_str() {
+        if let Some(value) = attr.value_str() {
             if let Ok(value) = FromStr::from_str(value.as_str()) {
                 f(value);
             } else {
@@ -133,7 +133,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name:
     }
 }
 
-pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> {
+pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: Symbol) -> Option<&'a A> {
     let mut unique_attr: Option<&A> = None;
     for attr in get_attr(sess, attrs, name) {
         if let Some(duplicate) = unique_attr {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index b9928b8eed4..6f5b0ec54cd 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -487,7 +487,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
             ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
             ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(lit) => {
-                if is_direct_expn_of(e.span, "cfg").is_some() {
+                if is_direct_expn_of(e.span, sym::cfg).is_some() {
                     None
                 } else {
                     Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
@@ -565,7 +565,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 })
             },
             ExprKind::Lit(lit) => {
-                if is_direct_expn_of(e.span, "cfg").is_some() {
+                if is_direct_expn_of(e.span, sym::cfg).is_some() {
                     None
                 } else {
                     match &lit.node {
@@ -654,7 +654,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                         span,
                         ..
                     }) = self.tcx.hir_node(body_id.hir_id)
-                    && is_direct_expn_of(*span, "cfg").is_some()
+                    && is_direct_expn_of(*span, sym::cfg).is_some()
                 {
                     return None;
                 }
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 4543a20cc2c..9d38672efad 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -10,6 +10,7 @@
 //!  - option-if-let-else
 
 use crate::consts::{ConstEvalCtxt, FullInt};
+use crate::sym;
 use crate::ty::{all_predicates_of, is_copy};
 use crate::visitors::is_const_evaluatable;
 use rustc_hir::def::{DefKind, Res};
@@ -19,7 +20,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_span::{Symbol, sym};
+use rustc_span::Symbol;
 use std::{cmp, ops};
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -49,14 +50,13 @@ impl ops::BitOrAssign for EagernessSuggestion {
 /// Determine the eagerness of the given function call.
 fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
-    let name = name.as_str();
 
     let ty = match cx.tcx.impl_of_method(fn_id) {
         Some(id) => cx.tcx.type_of(id).instantiate_identity(),
         None => return Lazy,
     };
 
-    if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
+    if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg {
         if matches!(
             cx.tcx.crate_name(fn_id.krate),
             sym::std | sym::core | sym::alloc | sym::proc_macro
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index dbb99348290..6971b488013 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -299,7 +299,7 @@ impl<'a> VecArgs<'a> {
     pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<VecArgs<'a>> {
         if let ExprKind::Call(fun, args) = expr.kind
             && let ExprKind::Path(ref qpath) = fun.kind
-            && is_expn_of(fun.span, "vec").is_some()
+            && is_expn_of(fun.span, sym::vec).is_some()
             && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
         {
             return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 0a9c39c41bd..3a319176571 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -25,8 +25,10 @@
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
+extern crate indexmap;
 extern crate rustc_abi;
 extern crate rustc_ast;
+extern crate rustc_attr_data_structures;
 extern crate rustc_attr_parsing;
 extern crate rustc_const_eval;
 extern crate rustc_data_structures;
@@ -81,17 +83,16 @@ pub use self::hir_utils::{
 use core::mem;
 use core::ops::ControlFlow;
 use std::collections::hash_map::Entry;
-use std::hash::BuildHasherDefault;
 use std::iter::{once, repeat_n};
 use std::sync::{Mutex, MutexGuard, OnceLock};
 
 use itertools::Itertools;
 use rustc_abi::Integer;
 use rustc_ast::ast::{self, LitKind, RangeLimits};
-use rustc_attr_parsing::{AttributeKind, find_attr};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::packed::Pu128;
-use rustc_data_structures::unhash::UnhashMap;
+use rustc_data_structures::unhash::UnindexMap;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
@@ -523,12 +524,8 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 ///     }
 /// }
 /// ```
-pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
-    // Get the implemented trait for the current function
-    let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-    let parent_impl = cx.tcx.hir_get_parent_item(hir_id);
-    if parent_impl != hir::CRATE_OWNER_ID
-        && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id)
+pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
+    if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
         && let ItemKind::Impl(impl_) = &item.kind
     {
         return impl_.of_trait.as_ref();
@@ -1101,13 +1098,13 @@ pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symb
 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
     let mut current = expr;
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
         if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
-            if path.ident.name.as_str() == *method_name {
+            if path.ident.name == *method_name {
                 if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
@@ -1493,14 +1490,14 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// macro `name`.
 /// See also [`is_direct_expn_of`].
 #[must_use]
-pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
+pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {
     loop {
         if span.from_expansion() {
             let data = span.ctxt().outer_expn_data();
             let new_span = data.call_site;
 
             if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
-                && mac_name.as_str() == name
+                && mac_name == name
             {
                 return Some(new_span);
             }
@@ -1523,13 +1520,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 /// from `bar!` by `is_direct_expn_of`.
 #[must_use]
-pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
+pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {
     if span.from_expansion() {
         let data = span.ctxt().outer_expn_data();
         let new_span = data.call_site;
 
         if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
-            && mac_name.as_str() == name
+            && mac_name == name
         {
             return Some(new_span);
         }
@@ -1793,11 +1790,11 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
 }
 
 /// Checks if the given `DefId` matches the `libc` item.
-pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
+pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {
     let path = cx.get_def_path(did);
     // libc is meant to be used as a flat list of names, but they're all actually defined in different
     // modules based on the target platform. Ignore everything but crate name and the item name.
-    path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name)
+    path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name)
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -2196,45 +2193,46 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     None
 }
 
-/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
-/// and `a` is before `b` in `exprs` for all `a` and `b` in
-/// `exprs`
+/// Returns a list of groups where elements in each group are equal according to `eq`
+///
+/// - Within each group the elements are sorted by the order they appear in `exprs`
+/// - The groups themselves are sorted by their first element's appearence in `exprs`
 ///
 /// Given functions `eq` and `hash` such that `eq(a, b) == true`
 /// implies `hash(a) == hash(b)`
-pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)>
+pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<Vec<&T>>
 where
     Hash: FnMut(&T) -> u64,
     Eq: FnMut(&T, &T) -> bool,
 {
     match exprs {
-        [a, b] if eq(a, b) => return vec![(a, b)],
+        [a, b] if eq(a, b) => return vec![vec![a, b]],
         _ if exprs.len() <= 2 => return vec![],
         _ => {},
     }
 
-    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
-
-    let mut map: UnhashMap<u64, Vec<&_>> =
-        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+    let mut buckets: UnindexMap<u64, Vec<Vec<&T>>> = UnindexMap::default();
 
     for expr in exprs {
-        match map.entry(hash(expr)) {
-            Entry::Occupied(mut o) => {
-                for o in o.get() {
-                    if eq(o, expr) {
-                        match_expr_list.push((o, expr));
-                    }
+        match buckets.entry(hash(expr)) {
+            indexmap::map::Entry::Occupied(mut o) => {
+                let bucket = o.get_mut();
+                match bucket.iter_mut().find(|group| eq(expr, group[0])) {
+                    Some(group) => group.push(expr),
+                    None => bucket.push(vec![expr]),
                 }
-                o.get_mut().push(expr);
             },
-            Entry::Vacant(v) => {
-                v.insert(vec![expr]);
+            indexmap::map::Entry::Vacant(v) => {
+                v.insert(vec![vec![expr]]);
             },
         }
     }
 
-    match_expr_list
+    buckets
+        .into_values()
+        .flatten()
+        .filter(|group| group.len() > 1)
+        .collect()
 }
 
 /// Peels off all references on the pattern. Returns the underlying pattern and the number of
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index dfb30b9c218..ba126fcd05d 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -2,8 +2,8 @@
 
 use std::sync::{Arc, OnceLock};
 
-use crate::get_unique_attr;
 use crate::visitors::{Descend, for_each_expr_without_closures};
+use crate::{get_unique_attr, sym};
 
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
@@ -12,7 +12,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
-use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym};
+use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol};
 use std::ops::ControlFlow;
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -42,7 +42,7 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
     } else {
         // Allow users to tag any macro as being format!-like
         // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method
-        get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some()
+        get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), sym::format_args).is_some()
     }
 }
 
@@ -248,10 +248,10 @@ impl<'a> PanicExpn<'a> {
         let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else {
             return None;
         };
-        let name = path.segments.last().unwrap().ident.as_str();
+        let name = path.segments.last().unwrap().ident.name;
 
         // This has no argument
-        if name == "panic_cold_explicit" {
+        if name == sym::panic_cold_explicit {
             return Some(Self::Empty);
         }
 
@@ -259,18 +259,18 @@ impl<'a> PanicExpn<'a> {
             return None;
         };
         let result = match name {
-            "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty,
-            "panic" | "panic_str" => Self::Str(arg),
-            "panic_display" | "panic_cold_display" => {
+            sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty,
+            sym::panic | sym::panic_str => Self::Str(arg),
+            sym::panic_display | sym::panic_cold_display => {
                 let ExprKind::AddrOf(_, _, e) = &arg.kind else {
                     return None;
                 };
                 Self::Display(e)
             },
-            "panic_fmt" => Self::Format(arg),
+            sym::panic_fmt => Self::Format(arg),
             // Since Rust 1.52, `assert_{eq,ne}` macros expand to use:
             // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));`
-            "assert_failed" => {
+            sym::assert_failed => {
                 // It should have 4 arguments in total (we already matched with the first argument,
                 // so we're just checking for 3)
                 if rest.len() != 3 {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 223a8649eb3..a5e66ad463b 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -1,7 +1,8 @@
 use crate::sym;
 use rustc_ast::Attribute;
 use rustc_ast::attr::AttributeExt;
-use rustc_attr_parsing::{RustcVersion, parse_version};
+use rustc_attr_data_structures::RustcVersion;
+use rustc_attr_parsing::parse_version;
 use rustc_lint::LateContext;
 use rustc_session::Session;
 use rustc_span::Symbol;
@@ -24,7 +25,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
     1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
-    1,85,0 { UINT_FLOAT_MIDPOINT }
+    1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
     1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index e5179e479cc..9d7f3086b05 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -129,6 +129,7 @@ path_macros! {
 // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
 pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of);
 pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit);
+pub static CONCAT: PathLookup = macro_path!(core::concat);
 pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new);
 pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other);
 pub static ITER_STEP: PathLookup = type_path!(core::iter::Step);
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 360c6251a57..5847e916e34 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -1,17 +1,17 @@
 use crate::source::snippet;
 use crate::visitors::{Descend, for_each_expr_without_closures};
-use crate::{path_to_local_id, strip_pat_refs};
+use crate::{path_to_local_id, strip_pat_refs, sym};
 use core::ops::ControlFlow;
 use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 pub fn get_spans(
     cx: &LateContext<'_>,
     opt_body_id: Option<BodyId>,
     idx: usize,
-    replacements: &[(&'static str, &'static str)],
+    replacements: &[(Symbol, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) {
         if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
@@ -27,7 +27,7 @@ pub fn get_spans(
 fn extract_clone_suggestions<'tcx>(
     cx: &LateContext<'tcx>,
     id: HirId,
-    replace: &[(&'static str, &'static str)],
+    replace: &[(Symbol, &'static str)],
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut spans = Vec::new();
@@ -35,11 +35,11 @@ fn extract_clone_suggestions<'tcx>(
         if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
             && path_to_local_id(recv, id)
         {
-            if seg.ident.as_str() == "capacity" {
+            if seg.ident.name == sym::capacity {
                 return ControlFlow::Break(());
             }
             for &(fn_name, suffix) in replace {
-                if seg.ident.as_str() == fn_name {
+                if seg.ident.name == fn_name {
                     spans.push((e.span, snippet(cx, recv.span, "_") + suffix));
                     return ControlFlow::Continue(Descend::No);
                 }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 5d0401010db..45da266fd8a 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -5,7 +5,7 @@
 
 use crate::msrvs::{self, Msrv};
 use hir::LangItem;
-use rustc_attr_parsing::{RustcVersion, StableSince};
+use rustc_attr_data_structures::{RustcVersion, StableSince};
 use rustc_const_eval::check_consts::ConstCx;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -404,7 +404,7 @@ fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
                     .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id))
             })
             .is_none_or(|const_stab| {
-                if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level {
+                if let rustc_attr_data_structures::StabilityLevel::Stable { since, .. } = const_stab.level {
                     // Checking MSRV is manually necessary because `rustc` has no such concept. This entire
                     // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
                     // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 8645d5730fe..7f2bf99daff 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -7,13 +7,14 @@ use std::sync::Arc;
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
+use rustc_lexer::{LiteralKind, TokenKind, tokenize};
 use rustc_lint::{EarlyContext, LateContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{SourceMap, original_sp};
 use rustc_span::{
-    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext,
-    hygiene,
+    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData,
+    SyntaxContext, hygiene,
 };
 use std::borrow::Cow;
 use std::fmt;
@@ -137,25 +138,25 @@ pub trait SpanRangeExt: SpanRange {
     fn map_range(
         self,
         cx: &impl HasSession,
-        f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+        f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>,
     ) -> Option<Range<BytePos>> {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
     #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")]
-    /// Extends the range to include all preceding whitespace characters, unless there
-    /// are non-whitespace characters left on the same line after `self`.
+    /// Extends the range to include all preceding whitespace characters.
+    ///
+    /// The range will not be expanded if it would cross a line boundary, the line the range would
+    /// be extended to ends with a line comment and the text after the range contains a
+    /// non-whitespace character on the same line. e.g.
     ///
-    /// This extra condition prevents a problem when removing the '}' in:
     /// ```ignore
-    ///   ( // There was an opening bracket after the parenthesis, which has been removed
-    ///     // This is a comment
-    ///    })
+    /// ( // Some comment
+    /// foo)
     /// ```
-    /// Removing the whitespaces, including the linefeed, before the '}', would put the
-    /// closing parenthesis at the end of the `// This is a comment` line, which would
-    /// make it part of the comment as well. In this case, it is best to keep the span
-    /// on the '}' alone.
+    ///
+    /// When the range points to `foo`, suggesting to remove the range after it's been extended will
+    /// cause the `)` to be placed inside the line comment as `( // Some comment)`.
     fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
@@ -254,11 +255,11 @@ fn with_source_text_and_range<T>(
 fn map_range(
     sm: &SourceMap,
     sp: Range<BytePos>,
-    f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+    f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>,
 ) -> Option<Range<BytePos>> {
     if let Some(src) = get_source_range(sm, sp.clone())
         && let Some(text) = &src.sf.src
-        && let Some(range) = f(text, src.range.clone())
+        && let Some(range) = f(&src.sf, text, src.range.clone())
     {
         debug_assert!(
             range.start <= text.len() && range.end <= text.len(),
@@ -275,20 +276,57 @@ fn map_range(
     }
 }
 
+fn ends_with_line_comment_or_broken(text: &str) -> bool {
+    let Some(last) = tokenize(text).last() else {
+        return false;
+    };
+    match last.kind {
+        // Will give the wrong result on text like `" // "` where the first quote ends a string
+        // started earlier. The only workaround is to lex the whole file which we don't really want
+        // to do.
+        TokenKind::LineComment { .. } | TokenKind::BlockComment { terminated: false, .. } => true,
+        TokenKind::Literal { kind, .. } => matches!(
+            kind,
+            LiteralKind::Byte { terminated: false }
+                | LiteralKind::ByteStr { terminated: false }
+                | LiteralKind::CStr { terminated: false }
+                | LiteralKind::Char { terminated: false }
+                | LiteralKind::RawByteStr { n_hashes: None }
+                | LiteralKind::RawCStr { n_hashes: None }
+                | LiteralKind::RawStr { n_hashes: None }
+        ),
+        _ => false,
+    }
+}
+
+fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range<usize>) -> Option<usize> {
+    debug_assert!(lines.is_empty() || lines[0].to_u32() == 0);
+
+    let start = src.get(..range.start)?.trim_end();
+    let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len());
+    if let Some(line_end) = lines.get(next_line)
+        && line_end.to_usize() <= range.start
+        && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize())
+        && ends_with_line_comment_or_broken(&start[prev_start..])
+        && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end)
+        && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize())
+        && tokenize(src.get(range.end..next_start)?).any(|t| !matches!(t.kind, TokenKind::Whitespace))
+    {
+        Some(range.start)
+    } else {
+        Some(start.len())
+    }
+}
+
 fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
-    map_range(sm, sp, |src, range| {
-        let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len();
-        if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) {
-            Some(src.get(..range.start)?.trim_end().len()..range.end)
-        } else {
-            Some(range)
-        }
+    map_range(sm, sp.clone(), |sf, src, range| {
+        Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end)
     })
-    .unwrap()
+    .unwrap_or(sp)
 }
 
 fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
-    map_range(sm, sp.clone(), |src, range| {
+    map_range(sm, sp.clone(), |_, src, range| {
         let src = src.get(range.clone())?;
         Some(range.start + (src.len() - src.trim_start().len())..range.end)
     })
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 9428262b99a..f417530be36 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -29,172 +29,330 @@ macro_rules! generate {
     };
 }
 
+// List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`).
+// An alternative content can be specified using a colon after the symbol name.
+//
+// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted.
 generate! {
+    AsyncReadExt,
+    AsyncWriteExt,
+    BACKSLASH_SINGLE_QUOTE: r"\'",
+    Binary,
+    CLIPPY_ARGS,
+    CLIPPY_CONF_DIR,
+    CRLF: "\r\n",
+    Cargo_toml: "Cargo.toml",
+    Current,
+    DOUBLE_QUOTE: "\"",
+    Deserialize,
+    EarlyLintPass,
+    ErrorKind,
+    IntoIter,
+    Itertools,
+    LF: "\n",
+    Lazy,
+    Lint,
+    LowerExp,
+    LowerHex,
+    MAX,
+    MIN,
+    MsrvStack,
+    Octal,
+    OpenOptions,
+    Other,
+    PathLookup,
+    Regex,
+    RegexBuilder,
+    RegexSet,
+    Start,
+    Step,
+    Symbol,
+    SyntaxContext,
+    TBD,
+    UpperExp,
+    UpperHex,
+    V4,
+    V6,
+    Visitor,
+    Weak,
     abs,
     align_of,
     ambiguous_glob_reexports,
+    append,
+    arg,
     as_bytes,
-    as_deref_mut,
     as_deref,
+    as_deref_mut,
     as_mut,
-    AsyncReadExt,
-    AsyncWriteExt,
-    BACKSLASH_SINGLE_QUOTE: r"\'",
-    Binary,
+    assert_failed,
+    author,
+    borrow,
+    borrow_mut,
     build_hasher,
+    by_ref,
     bytes,
+    capacity,
     cargo_clippy: "cargo-clippy",
-    Cargo_toml: "Cargo.toml",
     cast,
+    cast_const,
+    cast_mut,
+    ceil,
+    ceil_char_boundary,
+    chain,
     chars,
-    CLIPPY_ARGS,
-    CLIPPY_CONF_DIR,
+    checked_abs,
+    checked_add,
+    checked_isqrt,
+    checked_mul,
+    checked_pow,
+    checked_rem_euclid,
+    checked_sub,
+    clamp,
     clippy_utils,
     clone_into,
     cloned,
+    cognitive_complexity,
     collect,
     const_ptr,
     contains,
     copied,
-    CRLF: "\r\n",
-    Current,
+    copy_from,
+    copy_from_nonoverlapping,
+    copy_to,
+    copy_to_nonoverlapping,
+    count_ones,
+    cycle,
+    cyclomatic_complexity,
     de,
-    Deserialize,
     diagnostics,
     disallowed_types,
-    DOUBLE_QUOTE: "\"",
-    EarlyLintPass,
+    drain,
+    dump,
     ends_with,
     enum_glob_use,
+    enumerate,
+    err,
     error,
-    ErrorKind,
     exp,
+    expect_err,
+    expn_data,
     extend,
-    finish_non_exhaustive,
+    filter,
+    filter_map,
+    find,
+    find_map,
     finish,
+    finish_non_exhaustive,
+    first,
     flat_map,
+    flatten,
+    floor,
+    floor_char_boundary,
+    fold,
     for_each,
-    from_bytes_with_nul_unchecked,
     from_bytes_with_nul,
+    from_bytes_with_nul_unchecked,
     from_ptr,
     from_raw,
     from_ref,
+    from_str,
     from_str_radix,
     fs,
+    fuse,
     futures_util,
     get,
+    get_mut,
+    get_or_insert_with,
+    get_unchecked,
+    get_unchecked_mut,
+    has_significant_drop,
     hidden_glob_reexports,
     hygiene,
+    if_chain,
     insert,
+    inspect,
     int_roundings,
+    into,
     into_bytes,
+    into_ok,
     into_owned,
-    IntoIter,
     io,
     is_ascii,
+    is_char_boundary,
+    is_digit,
     is_empty,
     is_err,
+    is_file,
     is_none,
     is_ok,
     is_some,
+    isqrt,
     itertools,
-    Itertools,
+    join,
     kw,
     last,
     lazy_static,
-    Lazy,
-    LF: "\n",
-    Lint,
     ln,
+    lock,
     lock_api,
     log,
-    LowerExp,
-    LowerHex,
+    log10,
+    log2,
     macro_use_imports,
-    map_or_else,
+    map_break,
+    map_continue,
     map_or,
+    map_or_else,
+    match_indices,
+    matches,
     max,
-    MAX,
+    max_by,
+    max_by_key,
+    max_value,
+    maximum,
     mem,
     min,
-    MIN,
+    min_by,
+    min_by_key,
+    min_value,
+    minimum,
     mode,
     module_name_repetitions,
     msrv,
     msrvs,
-    MsrvStack,
     mut_ptr,
     mutex,
     needless_return,
+    next_back,
+    next_if,
+    next_if_eq,
     next_tuple,
-    Octal,
+    nth,
+    ok,
+    ok_or,
     once_cell,
-    OpenOptions,
+    open,
     or_default,
-    Other,
+    or_else,
+    or_insert,
+    or_insert_with,
+    outer_expn,
+    panic_cold_display,
+    panic_cold_explicit,
+    panic_display,
+    panic_str,
     parse,
-    PathLookup,
+    partition,
     paths,
+    peek,
+    peek_mut,
+    peekable,
+    pow,
     powf,
     powi,
+    product,
     push,
+    read_line,
+    read_to_end,
+    read_to_string,
     redundant_pub_crate,
     regex,
-    Regex,
-    RegexBuilder,
-    RegexSet,
+    rem_euclid,
+    repeat,
+    replace,
+    replacen,
     reserve,
     resize,
     restriction,
-    rustc_lint_defs,
+    rev,
+    rfind,
+    rmatch_indices,
+    rmatches,
+    round,
+    rposition,
+    rsplit,
+    rsplit_once,
+    rsplit_terminator,
+    rsplitn,
+    rsplitn_mut,
     rustc_lint,
+    rustc_lint_defs,
     rustc_span,
     rustfmt_skip,
     rwlock,
+    saturating_abs,
+    saturating_pow,
+    scan,
+    seek,
     serde,
     set_len,
     set_mode,
     set_readonly,
     signum,
     single_component_path_imports,
+    skip_while,
+    slice_mut_unchecked,
+    slice_unchecked,
+    sort,
+    sort_by,
+    sort_unstable_by,
     span_lint_and_then,
-    split_whitespace,
     split,
+    split_at,
+    split_at_checked,
+    split_at_mut,
+    split_at_mut_checked,
+    split_inclusive,
+    split_once,
+    split_terminator,
+    split_whitespace,
+    splitn,
+    splitn_mut,
     sqrt,
-    Start,
-    Step,
+    starts_with,
+    step_by,
+    strlen,
     style,
+    subsec_micros,
+    subsec_nanos,
+    sum,
     symbol,
-    Symbol,
-    SyntaxContext,
     take,
-    TBD,
+    take_while,
+    then,
     then_some,
     to_ascii_lowercase,
     to_ascii_uppercase,
     to_digit,
     to_lowercase,
+    to_os_string,
     to_owned,
+    to_path_buf,
     to_uppercase,
     tokio,
+    trim,
+    trim_end_matches,
+    trim_start_matches,
     unreachable_pub,
     unsafe_removed_from_name,
+    unused,
     unused_braces,
     unused_extern_crates,
     unused_import_braces,
     unused_trait_names,
-    unused,
     unwrap_err,
+    unwrap_err_unchecked,
     unwrap_or_default,
     unwrap_or_else,
-    UpperExp,
-    UpperHex,
-    V4,
-    V6,
-    Visitor,
+    unwrap_unchecked,
+    unzip,
+    utils,
+    wake,
     warnings,
-    Weak,
     wildcard_imports,
     with_capacity,
     wrapping_offset,
+    write,
+    writeln,
+    zip,
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 26d41cfb497..c50ad17bfad 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -1361,3 +1361,14 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         || ty.is_array()
         || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
 }
+
+/// Gets the index of a field by name.
+pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
+    match *ty.kind() {
+        ty::Adt(def, _) if def.is_union() || def.is_struct() => {
+            def.non_enum_variant().fields.iter().position(|f| f.name == name)
+        },
+        ty::Tuple(_) => name.as_str().parse::<usize>().ok(),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index da41bdd27bc..0b9ebe554f5 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-05-14"
+channel = "nightly-2025-05-21"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index f8acf88cf81..37adb14169a 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -96,16 +96,11 @@ fn track_files(psess: &mut ParseSess) {
 
     // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
     // it is rebuilt
-    #[expect(
-        clippy::collapsible_if,
-        reason = "Due to a bug in let_chains this if statement can't be collapsed"
-    )]
-    if cfg!(debug_assertions) {
-        if let Ok(current_exe) = env::current_exe()
-            && let Some(current_exe) = current_exe.to_str()
-        {
-            file_depinfo.insert(Symbol::intern(current_exe));
-        }
+    if cfg!(debug_assertions)
+        && let Ok(current_exe) = env::current_exe()
+        && let Some(current_exe) = current_exe.to_str()
+    {
+        file_depinfo.insert(Symbol::intern(current_exe));
     }
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
index 50567e32b1b..a3c35a31c33 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
@@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,100 +61,124 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
index 50567e32b1b..a3c35a31c33 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
@@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,100 +61,124 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
index ae5261dcc6d..3fdd706fc62 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
@@ -25,7 +25,19 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    |       ^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:71:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:8
+   |
+LL | struct EnumWithExternButAtWrongPosition {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: should be placed before `EnumWithoutExtern`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:55:8
+   |
+LL | struct EnumWithoutExtern {
+   |        ^^^^^^^^^^^^^^^^^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:1
    |
 LL | / impl CloneSelf for StructOrdered {
 LL | |
@@ -36,7 +48,7 @@ LL | | }
    | |_^
    |
 note: should be placed before the following item
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:61:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:77:1
    |
 LL | / impl Default for StructOrdered {
 LL | |     fn default() -> Self {
@@ -47,25 +59,25 @@ LL | | }
    | |_^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:167:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:1
    |
 LL | impl BasicEmptyTrait for StructOrdered {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before the following item
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:168:1
    |
 LL | / impl TraitUnordered for StructUnordered {
 LL | |     const A: bool = false;
@@ -76,25 +88,25 @@ LL | | }
    | |_^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,112 +136,136 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:191:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:207:11
    |
 LL |     const A: i8 = 1;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:190:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:206:11
    |
 LL |     const C: i8 = 0;
    |           ^
 
-error: aborting due to 18 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
index 90399470d4c..1cfed9790c1 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
@@ -52,6 +52,22 @@ enum EnumUnorderedAllowed {
     B,
 }
 
+struct EnumWithoutExtern {
+    r: u8,
+    g: u8,
+    //~^ arbitrary_source_item_ordering
+    b: u8,
+    //~^ arbitrary_source_item_ordering
+}
+
+#[repr(C)]
+struct EnumWithExternButAtWrongPosition {
+    //~[ord_within]^ arbitrary_source_item_ordering
+    r: u8,
+    g: u8,
+    b: u8,
+}
+
 struct StructOrdered {
     a: bool,
     b: bool,
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
index 6f5cc47ba6c..f695f9804d5 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
@@ -13,7 +13,7 @@ fn main() {
     //~^^^^^^ collapsible_if
 
     // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
-    if x == "hello"  // Inner comment
+    if x == "hello" // Inner comment
         && y == "world" {
             println!("Hello world!");
         }
@@ -26,7 +26,7 @@ fn main() {
         }
     //~^^^^^^ collapsible_if
 
-    if x == "hello"  /* Inner comment */
+    if x == "hello" /* Inner comment */
         && y == "world" {
             println!("Hello world!");
         }
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
index 357ce4ad32d..a12c2112f58 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
@@ -32,7 +32,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  // Inner comment
+LL ~     if x == "hello" // Inner comment
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
@@ -70,7 +70,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  /* Inner comment */
+LL ~     if x == "hello" /* Inner comment */
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
index e953a2a4e90..2a6097fb579 100644
--- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
@@ -11,9 +11,9 @@ fn issue10272() {
     // should trigger warning
     let x = Cell::new(true);
     if x.get() {
+        //~^ ifs_same_cond
     } else if !x.take() {
     } else if x.get() {
-        //~^ ifs_same_cond
     } else {
     }
 }
diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
index d67e7fca656..adc44358c4c 100644
--- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
@@ -1,14 +1,12 @@
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:15:15
-   |
-LL |     } else if x.get() {
-   |               ^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:13:8
    |
 LL |     if x.get() {
    |        ^^^^^^^
+...
+LL |     } else if x.get() {
+   |               ^^^^^^^
+   |
    = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]`
 
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 18f0e04a880..429c20f95e9 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -1,7 +1,9 @@
+#![allow(clippy::useless_vec)]
+#![warn(clippy::assign_op_pattern)]
+
 use core::num::Wrapping;
+use std::ops::{Mul, MulAssign};
 
-#[allow(dead_code, unused_assignments, clippy::useless_vec)]
-#[warn(clippy::assign_op_pattern)]
 fn main() {
     let mut a = 5;
     a += 1;
@@ -39,3 +41,35 @@ fn main() {
     v[0] = v[0] + v[1];
     let _ = || v[0] = v[0] + v[1];
 }
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf += cows.clone();
+    //~^ assign_op_pattern
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+}
+
+// check that we don't lint on op assign impls, because that's just the way to impl them
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Wrap(i64);
+
+impl Mul<i64> for Wrap {
+    type Output = Self;
+
+    fn mul(self, rhs: i64) -> Self {
+        Wrap(self.0 * rhs)
+    }
+}
+
+impl MulAssign<i64> for Wrap {
+    fn mul_assign(&mut self, rhs: i64) {
+        *self = *self * rhs
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index 8b05c74d860..480ff07f150 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -1,7 +1,9 @@
+#![allow(clippy::useless_vec)]
+#![warn(clippy::assign_op_pattern)]
+
 use core::num::Wrapping;
+use std::ops::{Mul, MulAssign};
 
-#[allow(dead_code, unused_assignments, clippy::useless_vec)]
-#[warn(clippy::assign_op_pattern)]
 fn main() {
     let mut a = 5;
     a = a + 1;
@@ -39,3 +41,35 @@ fn main() {
     v[0] = v[0] + v[1];
     let _ = || v[0] = v[0] + v[1];
 }
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf = buf + cows.clone();
+    //~^ assign_op_pattern
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+}
+
+// check that we don't lint on op assign impls, because that's just the way to impl them
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Wrap(i64);
+
+impl Mul<i64> for Wrap {
+    type Output = Self;
+
+    fn mul(self, rhs: i64) -> Self {
+        Wrap(self.0 * rhs)
+    }
+}
+
+impl MulAssign<i64> for Wrap {
+    fn mul_assign(&mut self, rhs: i64) {
+        *self = *self * rhs
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr
index 17f216ee4a0..881a333fbe4 100644
--- a/src/tools/clippy/tests/ui/assign_ops.stderr
+++ b/src/tools/clippy/tests/ui/assign_ops.stderr
@@ -1,5 +1,5 @@
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:7:5
+  --> tests/ui/assign_ops.rs:9:5
    |
 LL |     a = a + 1;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
@@ -8,64 +8,70 @@ LL |     a = a + 1;
    = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:9:5
+  --> tests/ui/assign_ops.rs:11:5
    |
 LL |     a = 1 + a;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:11:5
+  --> tests/ui/assign_ops.rs:13:5
    |
 LL |     a = a - 1;
    |     ^^^^^^^^^ help: replace it with: `a -= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:13:5
+  --> tests/ui/assign_ops.rs:15:5
    |
 LL |     a = a * 99;
    |     ^^^^^^^^^^ help: replace it with: `a *= 99`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:15:5
+  --> tests/ui/assign_ops.rs:17:5
    |
 LL |     a = 42 * a;
    |     ^^^^^^^^^^ help: replace it with: `a *= 42`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:17:5
+  --> tests/ui/assign_ops.rs:19:5
    |
 LL |     a = a / 2;
    |     ^^^^^^^^^ help: replace it with: `a /= 2`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:19:5
+  --> tests/ui/assign_ops.rs:21:5
    |
 LL |     a = a % 5;
    |     ^^^^^^^^^ help: replace it with: `a %= 5`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:21:5
+  --> tests/ui/assign_ops.rs:23:5
    |
 LL |     a = a & 1;
    |     ^^^^^^^^^ help: replace it with: `a &= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:28:5
+  --> tests/ui/assign_ops.rs:30:5
    |
 LL |     s = s + "bla";
    |     ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:33:5
+  --> tests/ui/assign_ops.rs:35:5
    |
 LL |     a = a + Wrapping(1u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:36:5
+  --> tests/ui/assign_ops.rs:38:5
    |
 LL |     v[0] = v[0] + v[1];
    |     ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]`
 
-error: aborting due to 11 previous errors
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:51:5
+   |
+LL |     buf = buf + cows.clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs
deleted file mode 100644
index 51867fa6962..00000000000
--- a/src/tools/clippy/tests/ui/assign_ops2.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-//@no-rustfix: overlapping suggestions
-#![allow(clippy::uninlined_format_args)]
-
-#[allow(unused_assignments)]
-#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
-fn main() {
-    let mut a = 5;
-    a += a + 1;
-    //~^ misrefactored_assign_op
-
-    a += 1 + a;
-    //~^ misrefactored_assign_op
-
-    a -= a - 1;
-    //~^ misrefactored_assign_op
-
-    a *= a * 99;
-    //~^ misrefactored_assign_op
-
-    a *= 42 * a;
-    //~^ misrefactored_assign_op
-
-    a /= a / 2;
-    //~^ misrefactored_assign_op
-
-    a %= a % 5;
-    //~^ misrefactored_assign_op
-
-    a &= a & 1;
-    //~^ misrefactored_assign_op
-
-    a *= a * a;
-    //~^ misrefactored_assign_op
-
-    a = a * a * a;
-    a = a * 42 * a;
-    a = a * 2 + a;
-    a -= 1 - a;
-    a /= 5 / a;
-    a %= 42 % a;
-    a <<= 6 << a;
-}
-
-// check that we don't lint on op assign impls, because that's just the way to impl them
-
-use std::ops::{Mul, MulAssign};
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct Wrap(i64);
-
-impl Mul<i64> for Wrap {
-    type Output = Self;
-
-    fn mul(self, rhs: i64) -> Self {
-        Wrap(self.0 * rhs)
-    }
-}
-
-impl MulAssign<i64> for Wrap {
-    fn mul_assign(&mut self, rhs: i64) {
-        *self = *self * rhs
-    }
-}
-
-fn cow_add_assign() {
-    use std::borrow::Cow;
-    let mut buf = Cow::Owned(String::from("bar"));
-    let cows = Cow::Borrowed("foo");
-
-    // this can be linted
-    buf = buf + cows.clone();
-    //~^ assign_op_pattern
-
-    // this should not as cow<str> Add is not commutative
-    buf = cows + buf;
-    println!("{}", buf);
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs
index 96e037d4fcd..96e037d4fcd 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
new file mode 100644
index 00000000000..0f439f78915
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
@@ -0,0 +1,221 @@
+//@aux-build:interior_mutable_const.rs
+
+#![deny(clippy::borrow_interior_mutable_const)]
+#![allow(
+    clippy::declare_interior_mutable_const,
+    clippy::out_of_bounds_indexing,
+    const_item_mutation,
+    unconditional_panic
+)]
+
+use core::cell::{Cell, UnsafeCell};
+use core::ops::{Deref, Index};
+
+trait ConstDefault {
+    const DEFAULT: Self;
+}
+impl ConstDefault for u32 {
+    const DEFAULT: Self = 0;
+}
+impl<T: ConstDefault> ConstDefault for Cell<T> {
+    const DEFAULT: Self = Cell::new(T::DEFAULT);
+}
+
+fn main() {
+    {
+        const C: String = String::new();
+        let _ = C;
+        let _ = &C;
+        let _ = C.len();
+        let _ = &*C;
+    }
+    {
+        const C: UnsafeCell<u32> = UnsafeCell::new(0);
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = C.into_inner();
+        let _ = C.get(); //~ borrow_interior_mutable_const
+    }
+    {
+        const C: Cell<u32> = Cell::new(0);
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &mut C; //~ borrow_interior_mutable_const
+        let _ = C.into_inner();
+
+        let local = C;
+        C.swap(&local) //~ borrow_interior_mutable_const
+    }
+    {
+        const C: [(Cell<u32>,); 1] = [(Cell::new(0),)];
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &C[0]; //~ borrow_interior_mutable_const
+        let _ = &C[0].0; //~ borrow_interior_mutable_const
+        C[0].0.set(1); //~ borrow_interior_mutable_const
+    }
+    {
+        struct S(Cell<u32>);
+        impl S {
+            const C: Self = Self(Cell::new(0));
+        }
+        impl Deref for S {
+            type Target = Cell<u32>;
+            fn deref(&self) -> &Self::Target {
+                &self.0
+            }
+        }
+        let _ = S::C;
+        let _ = S::C.0;
+        let _ = &S::C; //~ borrow_interior_mutable_const
+        let _ = &S::C.0; //~ borrow_interior_mutable_const
+        S::C.set(1); //~ borrow_interior_mutable_const
+        let _ = &*S::C; //~ borrow_interior_mutable_const
+        (*S::C).set(1); //~ borrow_interior_mutable_const
+    }
+    {
+        enum E {
+            Cell(Cell<u32>),
+            Other,
+        }
+        const CELL: E = E::Cell(Cell::new(0));
+        const OTHER: E = E::Other;
+
+        let _ = CELL;
+        let _ = &CELL; //~ borrow_interior_mutable_const
+        let E::Cell(_) = CELL else {
+            return;
+        };
+
+        let _ = OTHER;
+        let _ = &OTHER;
+        let E::Cell(ref _x) = OTHER else {
+            return;
+        };
+    }
+    {
+        struct S<T> {
+            cell: (Cell<T>, u32),
+            other: Option<T>,
+        }
+        impl<T: ConstDefault + Copy> S<T> {
+            const C: Self = Self {
+                cell: (Cell::<T>::DEFAULT, 0),
+                other: Some(T::DEFAULT),
+            };
+
+            fn f() {
+                let _ = Self::C;
+                let _ = &Self::C; //~ borrow_interior_mutable_const
+                let _ = Self::C.other;
+                let _ = &Self::C.other;
+                let _ = &Self::C.cell; //~ borrow_interior_mutable_const
+                let _ = &Self::C.cell.0; //~ borrow_interior_mutable_const
+                Self::C.cell.0.set(T::DEFAULT); //~ borrow_interior_mutable_const
+                let _ = &Self::C.cell.1;
+            }
+        }
+    }
+    {
+        trait T {
+            const VALUE: Option<Cell<u32>> = Some(Cell::new(0));
+        }
+        impl T for u32 {}
+        impl T for i32 {
+            const VALUE: Option<Cell<u32>> = None;
+        }
+
+        let _ = &u32::VALUE; //~ borrow_interior_mutable_const
+        let _ = &i32::VALUE;
+    }
+    {
+        trait Trait<T: ConstDefault> {
+            type T<U: ConstDefault>: ConstDefault;
+            const VALUE: Option<Self::T<T>> = Some(Self::T::<T>::DEFAULT);
+        }
+        impl<T: ConstDefault> Trait<T> for u32 {
+            type T<U: ConstDefault> = Cell<U>;
+        }
+        impl<T: ConstDefault> Trait<T> for i32 {
+            type T<U: ConstDefault> = Cell<U>;
+            const VALUE: Option<Cell<T>> = None;
+        }
+
+        fn f<T: ConstDefault>() {
+            let _ = &<u32 as Trait<T>>::VALUE; //~ borrow_interior_mutable_const
+            let _ = &<i32 as Trait<T>>::VALUE;
+        }
+    }
+    {
+        trait Trait {
+            const UNFROZEN: Option<Cell<u32>> = Some(Cell::new(0));
+            const FROZEN: Option<Cell<u32>> = None;
+            const NON_FREEZE: u32 = 0;
+        }
+        fn f<T: Trait>() {
+            // None of these are guaranteed to be frozen, so don't lint.
+            let _ = &T::UNFROZEN;
+            let _ = &T::FROZEN;
+            let _ = &T::NON_FREEZE;
+        }
+    }
+    {
+        struct S([Option<Cell<u32>>; 2]);
+        impl Index<usize> for S {
+            type Output = Option<Cell<u32>>;
+            fn index(&self, idx: usize) -> &Self::Output {
+                &self.0[idx]
+            }
+        }
+
+        const C: S = S([Some(Cell::new(0)), None]);
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &C[0]; //~ borrow_interior_mutable_const
+        let _ = &C.0[0]; //~ borrow_interior_mutable_const
+        let _ = &C.0[1];
+    }
+    {
+        const C: [Option<Cell<u32>>; 2] = [None, None];
+        let _ = &C[0];
+        let _ = &C[1];
+        let _ = &C[2];
+
+        fn f(i: usize) {
+            let _ = &C[i];
+        }
+    }
+    {
+        const C: [Option<Cell<u32>>; 2] = [None, Some(Cell::new(0))];
+        let _ = &C[0];
+        let _ = &C[1]; //~ borrow_interior_mutable_const
+        let _ = &C[2];
+
+        fn f(i: usize) {
+            let _ = &C[i]; //~ borrow_interior_mutable_const
+        }
+    }
+    {
+        let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
+        let _ = &interior_mutable_const::WRAPPED_PRIVATE_FROZEN_VARIANT;
+    }
+    {
+        type Cell2<T> = Cell<T>;
+        type MyCell = Cell2<u32>;
+        struct S(Option<MyCell>);
+        trait T {
+            type Assoc;
+        }
+        struct S2<T>(T, T, u32);
+        impl T for S {
+            type Assoc = S2<Self>;
+        }
+        type Assoc<X> = <X as T>::Assoc;
+        impl S {
+            const VALUE: Assoc<Self> = S2(Self(None), Self(Some(Cell::new(0))), 0);
+        }
+        let _ = &S::VALUE; //~ borrow_interior_mutable_const
+        let _ = &S::VALUE.0;
+        let _ = &S::VALUE.1; //~ borrow_interior_mutable_const
+        let _ = &S::VALUE.2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
new file mode 100644
index 00000000000..e7c3f879b05
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
@@ -0,0 +1,247 @@
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:35:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+note: the lint level is defined here
+  --> tests/ui/borrow_interior_mutable_const.rs:3:9
+   |
+LL | #![deny(clippy::borrow_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:37:17
+   |
+LL |         let _ = C.get();
+   |                 ^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:42:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:43:17
+   |
+LL |         let _ = &mut C;
+   |                 ^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:47:9
+   |
+LL |         C.swap(&local)
+   |         ^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:52:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:53:17
+   |
+LL |         let _ = &C[0];
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:54:17
+   |
+LL |         let _ = &C[0].0;
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:55:9
+   |
+LL |         C[0].0.set(1);
+   |         ^^^^^^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:70:17
+   |
+LL |         let _ = &S::C;
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:71:17
+   |
+LL |         let _ = &S::C.0;
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:72:9
+   |
+LL |         S::C.set(1);
+   |         ^^^^
+   |
+   = note: there is a compiler inserted call to `Deref::deref` here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:73:18
+   |
+LL |         let _ = &*S::C;
+   |                  ^^^^^
+   |
+   = note: this deref expression is a call to `Deref::deref`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:74:9
+   |
+LL |         (*S::C).set(1);
+   |         ^^^^^^^
+   |
+   = note: this deref expression is a call to `Deref::deref`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:85:17
+   |
+LL |         let _ = &CELL;
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:109:25
+   |
+LL |                 let _ = &Self::C;
+   |                         ^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:112:25
+   |
+LL |                 let _ = &Self::C.cell;
+   |                         ^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:113:25
+   |
+LL |                 let _ = &Self::C.cell.0;
+   |                         ^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:114:17
+   |
+LL |                 Self::C.cell.0.set(T::DEFAULT);
+   |                 ^^^^^^^^^^^^^^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:128:17
+   |
+LL |         let _ = &u32::VALUE;
+   |                 ^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:145:21
+   |
+LL |             let _ = &<u32 as Trait<T>>::VALUE;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:172:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:173:18
+   |
+LL |         let _ = &C[0];
+   |                  ^^^^
+   |
+   = note: this index expression is a call to `Index::index`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:174:17
+   |
+LL |         let _ = &C.0[0];
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:190:17
+   |
+LL |         let _ = &C[1];
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:194:21
+   |
+LL |             let _ = &C[i];
+   |                     ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:198:17
+   |
+LL |         let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:216:17
+   |
+LL |         let _ = &S::VALUE;
+   |                 ^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:218:17
+   |
+LL |         let _ = &S::VALUE.1;
+   |                 ^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: aborting due to 29 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs
deleted file mode 100644
index da940a4cfb5..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-//@aux-build:helper.rs
-
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const)]
-
-// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions.
-
-extern crate helper;
-
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-enum OptionalCell {
-    Unfrozen(Cell<bool>),
-    Frozen,
-}
-
-const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-fn borrow_optional_cell() {
-    let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability
-    let _ = &FROZEN_VARIANT;
-}
-
-trait AssocConsts {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-    const TO_BE_FROZEN_VARIANT: OptionalCell;
-
-    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    fn function() {
-        // This is the "suboptimal behavior" mentioned in `is_value_unfrozen`
-        // caused by a similar reason to unfrozen types without any default values
-        // get linted even if it has frozen variants'.
-        let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability
-
-        // The lint ignores default values because an impl of this trait can set
-        // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`.
-        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability
-    }
-}
-
-impl AssocConsts for u64 {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    fn function() {
-        let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &<Self as AssocConsts>::TO_BE_FROZEN_VARIANT;
-        let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
-    }
-}
-
-trait AssocTypes {
-    type ToBeUnfrozen;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-
-    // there's no need to test here because it's the exactly same as `trait::AssocTypes`
-    fn function();
-}
-
-impl AssocTypes for u64 {
-    type ToBeUnfrozen = AtomicUsize;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
-
-    fn function() {
-        let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &<Self as AssocTypes>::TO_BE_FROZEN_VARIANT;
-    }
-}
-
-enum BothOfCellAndGeneric<T> {
-    Unfrozen(Cell<*const T>),
-    Generic(*const T),
-    Frozen(usize),
-}
-
-impl<T> BothOfCellAndGeneric<T> {
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
-
-    fn function() {
-        let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::FROZEN_VARIANT;
-    }
-}
-
-fn main() {
-    // constants defined in foreign crates
-    let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-    let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT;
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
deleted file mode 100644
index 43850384b90..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
+++ /dev/null
@@ -1,79 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:22:14
-   |
-LL |     let _ = &UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:37:18
-   |
-LL |         let _ = &Self::TO_BE_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:41:18
-   |
-LL |         let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:50:18
-   |
-LL |         let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:52:18
-   |
-LL |         let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:74:18
-   |
-LL |         let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:91:18
-   |
-LL |         let _ = &Self::UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:92:18
-   |
-LL |         let _ = &Self::GENERIC_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:99:14
-   |
-LL |     let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 9 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
deleted file mode 100644
index fa729b62d7f..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)]
-#![allow(const_item_mutation)]
-
-use std::borrow::Cow;
-use std::cell::{Cell, UnsafeCell};
-use std::fmt::Display;
-use std::sync::Once;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-const CELL: Cell<usize> = Cell::new(6);
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Option<Box<AtomicUsize>>, u8) = ([ATOMIC], None, 7);
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-const NO_ANN: &dyn Display = &70;
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-const ONCE_INIT: Once = Once::new();
-
-// This is just a pointer that can be safely dereferenced,
-// it's semantically the same as `&'static T`;
-// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
-// For more information, please see the issue #5918.
-pub struct StaticRef<T> {
-    ptr: *const T,
-}
-
-impl<T> StaticRef<T> {
-    /// Create a new `StaticRef` from a raw pointer
-    ///
-    /// ## Safety
-    ///
-    /// Callers must pass in a reference to statically allocated memory which
-    /// does not overlap with other values.
-    pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
-        StaticRef { ptr }
-    }
-}
-
-impl<T> std::ops::Deref for StaticRef<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        unsafe { &*self.ptr }
-    }
-}
-
-// ICE regression test
-mod issue12979 {
-    use std::cell::UnsafeCell;
-
-    const ATOMIC_TUPLE: (Vec<UnsafeCell<u8>>, ()) = (Vec::new(), ());
-
-    fn main() {
-        let _x = &ATOMIC_TUPLE.0;
-    }
-}
-
-// use a tuple to make sure referencing a field behind a pointer isn't linted.
-const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
-
-fn main() {
-    ATOMIC.store(1, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
-    //~^ borrow_interior_mutable_const
-
-    let _once = ONCE_INIT;
-    let _once_ref = &ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_2 = &&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_4 = &&&&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_mut = &mut ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _atomic_into_inner = ATOMIC.into_inner();
-    // these should be all fine.
-    let _twice = (ONCE_INIT, ONCE_INIT);
-    let _ref_twice = &(ONCE_INIT, ONCE_INIT);
-    let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
-    let _array_twice = [ONCE_INIT, ONCE_INIT];
-    let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
-    let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
-
-    // referencing projection is still bad.
-    let _ = &ATOMIC_TUPLE;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0;
-    //~^ borrow_interior_mutable_const
-    let _ = &(&&&&ATOMIC_TUPLE).0;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
-    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.2;
-    let _ = (&&&&ATOMIC_TUPLE).0;
-    let _ = (&&&&ATOMIC_TUPLE).2;
-    let _ = ATOMIC_TUPLE.0;
-    let _ = ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
-    let _ = ATOMIC_TUPLE.1.into_iter();
-    let _ = ATOMIC_TUPLE.2;
-    let _ = &{ ATOMIC_TUPLE };
-
-    CELL.set(2);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(CELL.get(), 6);
-    //~^ borrow_interior_mutable_const
-
-    assert_eq!(INTEGER, 8);
-    assert!(STRING.is_empty());
-
-    let a = ATOMIC;
-    a.store(4, Ordering::SeqCst);
-    assert_eq!(a.load(Ordering::SeqCst), 4);
-
-    STATIC_TUPLE.0.store(3, Ordering::SeqCst);
-    assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
-    assert!(STATIC_TUPLE.1.is_empty());
-
-    assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
-
-    let _ = &CELL_REF.0;
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
deleted file mode 100644
index decea153f71..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ /dev/null
@@ -1,119 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:65:5
-   |
-LL |     ATOMIC.store(1, Ordering::SeqCst);
-   |     ^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/others.rs:1:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:67:16
-   |
-LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
-   |                ^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:71:22
-   |
-LL |     let _once_ref = &ONCE_INIT;
-   |                      ^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:73:25
-   |
-LL |     let _once_ref_2 = &&ONCE_INIT;
-   |                         ^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:75:27
-   |
-LL |     let _once_ref_4 = &&&&ONCE_INIT;
-   |                           ^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:77:26
-   |
-LL |     let _once_mut = &mut ONCE_INIT;
-   |                          ^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:89:14
-   |
-LL |     let _ = &ATOMIC_TUPLE;
-   |              ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:91:14
-   |
-LL |     let _ = &ATOMIC_TUPLE.0;
-   |              ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:93:19
-   |
-LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
-   |                   ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:95:14
-   |
-LL |     let _ = &ATOMIC_TUPLE.0[0];
-   |              ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:97:13
-   |
-LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:103:13
-   |
-LL |     let _ = ATOMIC_TUPLE.0[0];
-   |             ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:109:5
-   |
-LL |     CELL.set(2);
-   |     ^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:111:16
-   |
-LL |     assert_eq!(CELL.get(), 6);
-   |                ^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 14 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs
deleted file mode 100644
index bbe5538fbe1..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![deny(clippy::declare_interior_mutable_const)]
-
-// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139
-
-use std::cell::UnsafeCell;
-
-trait Trait {
-    type Assoc;
-}
-
-type Assoc<T> = <T as Trait>::Assoc;
-
-impl Trait for u8 {
-    type Assoc = UnsafeCell<u8>;
-}
-
-impl Trait for () {
-    type Assoc = ();
-}
-
-enum MaybeMutable {
-    Mutable(Assoc<u8>),
-    Immutable(Assoc<()>),
-}
-
-const CELL: Assoc<u8> = UnsafeCell::new(0); //~ ERROR: interior mutable
-const UNIT: Assoc<()> = ();
-const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable
-const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT);
-
-fn print_ref<T>(t: &T) {
-    let p: *const T = t;
-    println!("{p:p}")
-}
-
-fn main() {
-    print_ref(&CELL); //~ ERROR: interior mutability
-    print_ref(&UNIT);
-    print_ref(&MUTABLE); //~ ERROR: interior mutability
-    print_ref(&IMMUTABLE);
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr
deleted file mode 100644
index eabaf66560a..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1
-   |
-LL | const CELL: Assoc<u8> = UnsafeCell::new(0);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9
-   |
-LL | #![deny(clippy::declare_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1
-   |
-LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16
-   |
-LL |     print_ref(&CELL);
-   |                ^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16
-   |
-LL |     print_ref(&MUTABLE);
-   |                ^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
deleted file mode 100644
index c4878dbe57b..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
+++ /dev/null
@@ -1,219 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const)]
-
-// this file replicates its `declare` counterpart. Please see it for more discussions.
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-trait ConcreteTypes {
-    const ATOMIC: AtomicUsize;
-    const STRING: String;
-
-    fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::STRING;
-    }
-}
-
-impl ConcreteTypes for u64 {
-    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
-    const STRING: String = String::new();
-
-    fn function() {
-        // Lint this again since implementers can choose not to borrow it.
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::STRING;
-    }
-}
-
-// a helper trait used below
-trait ConstDefault {
-    const DEFAULT: Self;
-}
-
-trait GenericTypes<T, U> {
-    const TO_REMAIN_GENERIC: T;
-    const TO_BE_CONCRETE: U;
-
-    fn function() {
-        let _ = &Self::TO_REMAIN_GENERIC;
-    }
-}
-
-impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for Vec<T> {
-    const TO_REMAIN_GENERIC: T = T::DEFAULT;
-    const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-
-    fn function() {
-        let _ = &Self::TO_REMAIN_GENERIC;
-        let _ = &Self::TO_BE_CONCRETE;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-// a helper type used below
-pub struct Wrapper<T>(T);
-
-trait AssocTypes {
-    type ToBeFrozen;
-    type ToBeUnfrozen;
-    type ToBeGenericParam;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
-
-    fn function() {
-        let _ = &Self::TO_BE_FROZEN;
-        let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-    }
-}
-
-impl<T: ConstDefault> AssocTypes for Vec<T> {
-    type ToBeFrozen = u16;
-    type ToBeUnfrozen = AtomicUsize;
-    type ToBeGenericParam = T;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen = 12;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
-
-    fn function() {
-        let _ = &Self::TO_BE_FROZEN;
-        let _ = &Self::TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM;
-    }
-}
-
-// a helper trait used below
-trait AssocTypesHelper {
-    type NotToBeBounded;
-    type ToBeBounded;
-
-    const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
-}
-
-trait AssocTypesFromGenericParam<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded;
-    const BOUNDED: T::ToBeBounded;
-
-    fn function() {
-        let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-impl<T> AssocTypesFromGenericParam<T> for Vec<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
-
-    fn function() {
-        let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-trait SelfType: Sized {
-    const SELF: Self;
-    const WRAPPED_SELF: Option<Self>;
-
-    fn function() {
-        let _ = &Self::SELF;
-        let _ = &Self::WRAPPED_SELF;
-    }
-}
-
-impl SelfType for u64 {
-    const SELF: Self = 16;
-    const WRAPPED_SELF: Option<Self> = Some(20);
-
-    fn function() {
-        let _ = &Self::SELF;
-        let _ = &Self::WRAPPED_SELF;
-    }
-}
-
-impl SelfType for AtomicUsize {
-    const SELF: Self = AtomicUsize::new(17);
-    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-
-    fn function() {
-        let _ = &Self::SELF;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_SELF;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-trait BothOfCellAndGeneric<T> {
-    const DIRECT: Cell<T>;
-    const INDIRECT: Cell<*const T>;
-
-    fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
-    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-    const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
-
-    fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-struct Local<T>(T);
-
-impl<T> Local<T>
-where
-    T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-    const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-
-    const GENERIC_TYPE: T = T::DEFAULT;
-
-    const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-
-    fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::COW;
-        let _ = &Self::GENERIC_TYPE;
-        let _ = &Self::ASSOC_TYPE;
-        let _ = &Self::BOUNDED_ASSOC_TYPE;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-fn main() {
-    u64::ATOMIC.store(5, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
-    //~^ borrow_interior_mutable_const
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
deleted file mode 100644
index cad68ca9260..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
+++ /dev/null
@@ -1,143 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:15:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:53:18
-   |
-LL |         let _ = &Self::TO_BE_CONCRETE;
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:89:18
-   |
-LL |         let _ = &Self::TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:91:18
-   |
-LL |         let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:114:18
-   |
-LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:128:18
-   |
-LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:158:18
-   |
-LL |         let _ = &Self::SELF;
-   |                  ^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:160:18
-   |
-LL |         let _ = &Self::WRAPPED_SELF;
-   |                  ^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:170:18
-   |
-LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18
-   |
-LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:182:18
-   |
-LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:184:18
-   |
-LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:204:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:209:18
-   |
-LL |         let _ = &Self::BOUNDED_ASSOC_TYPE;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:215:5
-   |
-LL |     u64::ATOMIC.store(5, Ordering::SeqCst);
-   |     ^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:217:16
-   |
-LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
-   |                ^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 17 previous errors
-
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 88c2549f4dc..77329cf5455 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: only some diagnostics have suggestions
 
 #![feature(repr128)]
 #![allow(incomplete_features)]
diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs
index e9240180886..e5bef2a99d5 100644
--- a/src/tools/clippy/tests/ui/cast_size.rs
+++ b/src/tools/clippy/tests/ui/cast_size.rs
@@ -1,7 +1,7 @@
 //@revisions: 32bit 64bit
 //@[32bit]ignore-bitwidth: 64
 //@[64bit]ignore-bitwidth: 32
-//@no-rustfix
+//@no-rustfix: only some diagnostics have suggestions
 
 #![warn(
     clippy::cast_precision_loss,
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
index 145885702a9..7635f848cb3 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
@@ -4,7 +4,7 @@
     clippy::branches_sharing_code,
     clippy::unnecessary_literal_unwrap
 )]
-//@no-rustfix
+//@no-rustfix: has placeholders
 fn test_nested() {
     fn nested() {
         let x = Some(());
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index ba0d36d85fe..785b2473c05 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -1,4 +1,4 @@
-//@no-rustfix: overlapping suggestions
+//@no-rustfix: has placeholders
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
 #![allow(
     clippy::if_same_then_else,
diff --git a/src/tools/clippy/tests/ui/comparison_chain.rs b/src/tools/clippy/tests/ui/comparison_chain.rs
index 669690a4d42..6db75a4f364 100644
--- a/src/tools/clippy/tests/ui/comparison_chain.rs
+++ b/src/tools/clippy/tests/ui/comparison_chain.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: has placeholders
 #![allow(dead_code)]
 #![warn(clippy::comparison_chain)]
 
@@ -12,11 +12,10 @@ fn f(x: u8, y: u8, z: u8) {
         a()
     }
 
-    if x > y {
-        //~^ comparison_chain
-
+    // Ignored: Not all cases are covered
+    if x < y {
         a()
-    } else if x < y {
+    } else if x > y {
         b()
     }
 
@@ -123,9 +122,8 @@ fn g(x: f64, y: f64, z: f64) {
 }
 
 fn h<T: Ord>(x: T, y: T, z: T) {
+    // Ignored: Not all cases are covered
     if x > y {
-        //~^ comparison_chain
-
         a()
     } else if x < y {
         b()
diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr
index 0256573d0d9..ce580bd54a1 100644
--- a/src/tools/clippy/tests/ui/comparison_chain.stderr
+++ b/src/tools/clippy/tests/ui/comparison_chain.stderr
@@ -1,12 +1,12 @@
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:15:5
+  --> tests/ui/comparison_chain.rs:29:5
    |
 LL | /     if x > y {
 LL | |
 LL | |
 LL | |         a()
-LL | |     } else if x < y {
-LL | |         b()
+...  |
+LL | |         c()
 LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
    |
@@ -14,19 +14,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:30:5
-   |
-LL | /     if x > y {
-LL | |
-LL | |
-LL | |         a()
-...  |
-LL | |         c()
-LL | |     }
-   | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
-
-error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:40:5
+  --> tests/ui/comparison_chain.rs:39:5
    |
 LL | /     if x > y {
 LL | |
@@ -38,7 +26,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:50:5
+  --> tests/ui/comparison_chain.rs:49:5
    |
 LL | /     if x > 1 {
 LL | |
@@ -50,19 +38,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:126:5
-   |
-LL | /     if x > y {
-LL | |
-LL | |
-LL | |         a()
-LL | |     } else if x < y {
-LL | |         b()
-LL | |     }
-   | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
-
-error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:134:5
+  --> tests/ui/comparison_chain.rs:132:5
    |
 LL | /     if x > y {
 LL | |
@@ -74,7 +50,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:144:5
+  --> tests/ui/comparison_chain.rs:142:5
    |
 LL | /     if x > y {
 LL | |
@@ -86,7 +62,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:251:5
+  --> tests/ui/comparison_chain.rs:249:5
    |
 LL | /     if x + 1 > y * 2 {
 LL | |
@@ -97,5 +73,5 @@ LL | |         "cc"
 LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match (x + 1).cmp(&(y * 2)) {...}`
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
index ab9c61463e9..8a31eb9550b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
@@ -3,6 +3,6 @@
 fn main() {
     if (true) {
         // anything一些中文
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.rs b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
index b774bd3788a..013aadadce5 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
@@ -4,6 +4,6 @@ fn main() {
     if (true) {
         // anything一些中文
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.stderr b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
index 7cc418898e8..4b77299dd5e 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
@@ -1,10 +1,8 @@
 error: unneeded `return` statement
-  --> tests/ui/crashes/ice-12491.rs:5:24
+  --> tests/ui/crashes/ice-12491.rs:6:9
    |
-LL |           // anything一些中文
-   |  ____________________________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
    = note: `-D clippy::needless-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_return)]`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed b/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed
new file mode 100644
index 00000000000..e68f1c20a8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed
@@ -0,0 +1,2 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed b/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed
new file mode 100644
index 00000000000..e89fa636d4b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed
@@ -0,0 +1,3 @@
+#![deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.rs b/src/tools/clippy/tests/ui/crashes/ice-12979.rs
new file mode 100644
index 00000000000..a2787291d9e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.rs
@@ -0,0 +1,3 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.stderr b/src/tools/clippy/tests/ui/crashes/ice-12979.stderr
new file mode 100644
index 00000000000..5e760816164
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.stderr
@@ -0,0 +1,19 @@
+error: empty line after outer attribute
+  --> tests/ui/crashes/ice-12979.rs:1:1
+   |
+LL | / #[deny(clippy::declare_interior_mutable_const)]
+LL | |
+   | |_^
+LL |   const FOO: u8 = 0;
+   |   --------- the attribute applies to this constant item
+   |
+   = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
+   = help: if the empty line is unintentional, remove it
+help: if the attribute should apply to the crate use an inner attribute
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |  +
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6840.rs b/src/tools/clippy/tests/ui/crashes/ice-6840.rs
index 94481f24899..f30d83e1eee 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6840.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6840.rs
@@ -2,6 +2,7 @@
 //! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840.
 //! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough
 #![allow(dead_code)]
+#![deny(clippy::zero_sized_map_values)] // For ICE 14822
 use std::collections::HashMap;
 
 pub trait Rule {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.rs b/src/tools/clippy/tests/ui/crashes/ice-9445.rs
deleted file mode 100644
index 232b8e4a795..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-9445.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-//~^ declare_interior_mutable_const
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr
deleted file mode 100644
index 76689cd6f5c..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/crashes/ice-9445.rs:1:1
-   |
-LL | const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
index 1a5119651b5..96b35c9a20c 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: overlapping suggestions
 //@error-in-other-file:
 #![warn(clippy::dbg_macro)]
 
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
new file mode 100644
index 00000000000..c65df275038
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
@@ -0,0 +1,200 @@
+#![deny(clippy::declare_interior_mutable_const)]
+#![allow(clippy::missing_const_for_thread_local)]
+
+use core::cell::{Cell, RefCell, UnsafeCell};
+use core::mem::{ManuallyDrop, MaybeUninit};
+use core::ptr;
+use core::sync::atomic::AtomicUsize;
+
+fn main() {}
+
+const _: Cell<u32> = Cell::new(0);
+const UNSAFE_CELL: UnsafeCell<u32> = UnsafeCell::new(0); //~ declare_interior_mutable_const
+const REF_CELL: RefCell<u32> = RefCell::new(0); //~ declare_interior_mutable_const
+const CELL: Cell<u32> = Cell::new(0); //~ declare_interior_mutable_const
+
+// Constants can't contain pointers or references to type with interior mutability.
+const fn make_ptr() -> *const Cell<u32> {
+    ptr::null()
+}
+const PTR: *const Cell<u32> = make_ptr();
+
+const fn casted_to_cell_ptr() -> *const Cell<u32> {
+    const VALUE: u32 = 0;
+    &VALUE as *const _ as *const Cell<u32>
+}
+const TRANSMUTED_PTR: *const Cell<u32> = casted_to_cell_ptr();
+
+const CELL_TUPLE: (bool, Cell<u32>) = (true, Cell::new(0)); //~ declare_interior_mutable_const
+const CELL_ARRAY: [Cell<u32>; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const
+
+const UNINIT_CELL: MaybeUninit<Cell<&'static ()>> = MaybeUninit::uninit();
+
+struct CellStruct {
+    x: u32,
+    cell: Cell<u32>,
+}
+//~v declare_interior_mutable_const
+const CELL_STRUCT: CellStruct = CellStruct {
+    x: 0,
+    cell: Cell::new(0),
+};
+
+enum CellEnum {
+    Cell(Cell<u32>),
+}
+const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const
+
+const NONE_CELL: Option<Cell<u32>> = None;
+const SOME_CELL: Option<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
+
+struct NestedCell([(Option<Cell<u32>>,); 1]);
+const NONE_NESTED_CELL: NestedCell = NestedCell([(None,)]);
+const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); //~ declare_interior_mutable_const
+
+union UnionCell {
+    cell: ManuallyDrop<Cell<u32>>,
+    x: u32,
+}
+//~v declare_interior_mutable_const
+const UNION_CELL: UnionCell = UnionCell {
+    cell: ManuallyDrop::new(Cell::new(0)),
+};
+// Access to either union field is valid so we have to be conservative here.
+const UNION_U32: UnionCell = UnionCell { x: 0 }; //~ declare_interior_mutable_const
+
+struct Assoc;
+impl Assoc {
+    const SELF: Self = Self;
+    const CELL: Cell<u32> = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+struct AssocCell(Cell<u32>);
+impl AssocCell {
+    const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const
+    const NONE_SELF: Option<Self> = None;
+    const SOME_SELF: Option<Self> = Some(Self(Cell::new(0))); //~ declare_interior_mutable_const
+}
+
+trait ConstDefault {
+    // May or may not be `Freeze`
+    const DEFAULT: Self;
+}
+impl ConstDefault for u32 {
+    const DEFAULT: Self = 0;
+}
+impl<T: ConstDefault> ConstDefault for Cell<T> {
+    // Interior mutability is forced by the trait.
+    const DEFAULT: Self = Cell::new(T::DEFAULT);
+}
+impl<T: ConstDefault> ConstDefault for Option<Cell<T>> {
+    // Could have been `None`
+    const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
+}
+
+enum GenericEnumCell<T> {
+    Cell(Cell<T>),
+    Other(T),
+}
+impl<T: ConstDefault> ConstDefault for GenericEnumCell<T> {
+    const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
+}
+impl<T: ConstDefault> GenericEnumCell<T> {
+    const CELL: Self = Self::DEFAULT; //~ declare_interior_mutable_const
+    const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); //~ declare_interior_mutable_const
+    const OTHER: Self = Self::Other(T::DEFAULT);
+    const FROM_OTHER: Self = Self::OTHER;
+}
+
+enum GenericNestedEnumCell<T> {
+    GenericEnumCell(GenericEnumCell<T>),
+    EnumCell(GenericEnumCell<u32>),
+    Other(T),
+}
+impl<T: ConstDefault> GenericNestedEnumCell<T> {
+    const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::<T>::FROM_OTHER);
+    const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::<T>::CELL); //~ declare_interior_mutable_const
+    const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::<u32>::FROM_OTHER);
+    const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::<u32>::CELL); //~ declare_interior_mutable_const
+}
+
+trait CellTrait: ConstDefault + Sized {
+    // Must be non-`Freeze` due to the type
+    const CELL: Cell<Self>; //~ declare_interior_mutable_const
+    // May be non-`Freeze`, but may not be
+    const OPTION_CELL: Option<Cell<Self>>;
+    // May get redefined by the impl, but the default is non-`Freeze`.
+    const SOME_CELL: Option<Cell<Self>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
+    // May get redefined by the impl, but the default is `Freeze`.
+    const NONE_CELL: Option<Cell<Self>> = None;
+}
+
+trait CellWithAssoc {
+    type T;
+    const DEFAULT: Self::T;
+    // Must be non-`Freeze` due to the type
+    const CELL: Cell<Self::T>; //~ declare_interior_mutable_const
+    // May be non-`Freeze`, but may not be
+    const OPTION_CELL: Option<Cell<Self::T>>;
+    // May get redefined by the impl, but the default is non-`Freeze`.
+    const SOME_CELL: Option<Cell<Self::T>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
+    // May get redefined by the impl, but the default is `Freeze`.
+    const NONE_CELL: Option<Cell<Self::T>> = None;
+}
+
+impl CellWithAssoc for () {
+    type T = u32;
+    const DEFAULT: Self::T = 0;
+    const CELL: Cell<Self::T> = Cell::new(0);
+    const OPTION_CELL: Option<Cell<Self::T>> = None;
+}
+
+trait WithAssoc {
+    type T;
+    const VALUE: Self::T;
+}
+
+impl WithAssoc for u32 {
+    type T = Cell<u32>;
+    // The cell comes from the impl block, not the trait.
+    const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithLayeredAssoc {
+    type T: WithAssoc;
+    const VALUE: <Self::T as WithAssoc>::T;
+}
+
+impl WithLayeredAssoc for u32 {
+    type T = u32;
+    // The cell comes from the impl block, not the trait.
+    const VALUE: <Self::T as WithAssoc>::T = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithGenericAssoc {
+    type T<U>;
+    const VALUE: Self::T<u32>;
+}
+
+impl WithGenericAssoc for u32 {
+    type T<U> = Cell<U>;
+    const VALUE: Self::T<u32> = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithGenericAssocCell {
+    type T<U>;
+    const VALUE: Self::T<Cell<u32>>;
+}
+
+impl WithGenericAssocCell for u32 {
+    type T<U> = Option<U>;
+    const VALUE: Self::T<Cell<u32>> = None;
+}
+
+impl WithGenericAssocCell for i32 {
+    type T<U> = Option<U>;
+    const VALUE: Self::T<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
+}
+
+thread_local!(static THREAD_LOCAL_CELL: Cell<u32> = const { Cell::new(0) });
+thread_local!(static THREAD_LOCAL_CELL2: Cell<u32> = Cell::new(0));
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
new file mode 100644
index 00000000000..9742c17486c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
@@ -0,0 +1,197 @@
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:12:7
+   |
+LL | const UNSAFE_CELL: UnsafeCell<u32> = UnsafeCell::new(0);
+   |       ^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+note: the lint level is defined here
+  --> tests/ui/declare_interior_mutable_const.rs:1:9
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:13:7
+   |
+LL | const REF_CELL: RefCell<u32> = RefCell::new(0);
+   |       ^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:14:7
+   |
+LL | const CELL: Cell<u32> = Cell::new(0);
+   |       ^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:28:7
+   |
+LL | const CELL_TUPLE: (bool, Cell<u32>) = (true, Cell::new(0));
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:29:7
+   |
+LL | const CELL_ARRAY: [Cell<u32>; 2] = [Cell::new(0), Cell::new(0)];
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:38:7
+   |
+LL | const CELL_STRUCT: CellStruct = CellStruct {
+   |       ^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:46:7
+   |
+LL | const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0));
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:49:7
+   |
+LL | const SOME_CELL: Option<Cell<u32>> = Some(Cell::new(0));
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:53:7
+   |
+LL | const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]);
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:60:7
+   |
+LL | const UNION_CELL: UnionCell = UnionCell {
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:64:7
+   |
+LL | const UNION_U32: UnionCell = UnionCell { x: 0 };
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:69:11
+   |
+LL |     const CELL: Cell<u32> = Cell::new(0);
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:74:11
+   |
+LL |     const SELF: Self = Self(Cell::new(0));
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:76:11
+   |
+LL |     const SOME_SELF: Option<Self> = Some(Self(Cell::new(0)));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:92:11
+   |
+LL |     const DEFAULT: Self = Some(Cell::new(T::DEFAULT));
+   |           ^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:100:11
+   |
+LL |     const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT));
+   |           ^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:103:11
+   |
+LL |     const CELL: Self = Self::DEFAULT;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:104:11
+   |
+LL |     const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT);
+   |           ^^^^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:116:11
+   |
+LL |     const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::<T>::CELL);
+   |           ^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:118:11
+   |
+LL |     const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::<u32>::CELL);
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:123:11
+   |
+LL |     const CELL: Cell<Self>;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:127:11
+   |
+LL |     const SOME_CELL: Option<Cell<Self>> = Some(Cell::new(Self::DEFAULT));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:136:11
+   |
+LL |     const CELL: Cell<Self::T>;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:140:11
+   |
+LL |     const SOME_CELL: Option<Cell<Self::T>> = Some(Cell::new(Self::DEFAULT));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:160:11
+   |
+LL |     const VALUE: Self::T = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:171:11
+   |
+LL |     const VALUE: <Self::T as WithAssoc>::T = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:181:11
+   |
+LL |     const VALUE: Self::T<u32> = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:196:11
+   |
+LL |     const VALUE: Self::T<Cell<u32>> = Some(Cell::new(0));
+   |           ^^^^^
+
+error: aborting due to 28 previous errors
+
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs
deleted file mode 100644
index c87468277fb..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-enum OptionalCell {
-    Unfrozen(Cell<bool>),
-    Frozen,
-}
-
-// a constant with enums should be linted only when the used variant is unfrozen (#3962).
-const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-//~^ declare_interior_mutable_const
-const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-const fn unfrozen_variant() -> OptionalCell {
-    OptionalCell::Unfrozen(Cell::new(false))
-}
-
-const fn frozen_variant() -> OptionalCell {
-    OptionalCell::Frozen
-}
-
-const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-//~^ declare_interior_mutable_const
-const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
-
-enum NestedInnermost {
-    Unfrozen(AtomicUsize),
-    Frozen,
-}
-
-struct NestedInner {
-    inner: NestedInnermost,
-}
-
-enum NestedOuter {
-    NestedInner(NestedInner),
-    NotNested(usize),
-}
-
-struct NestedOutermost {
-    outer: NestedOuter,
-}
-
-// a constant with enums should be linted according to its value, no matter how structs involve.
-const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
-    //~^ declare_interior_mutable_const
-    outer: NestedOuter::NestedInner(NestedInner {
-        inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
-    }),
-};
-const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
-    outer: NestedOuter::NestedInner(NestedInner {
-        inner: NestedInnermost::Frozen,
-    }),
-};
-
-trait AssocConsts {
-    // When there's no default value, lint it only according to its type.
-    // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
-    const TO_BE_FROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
-
-    // Lint default values accordingly.
-    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    //~^ declare_interior_mutable_const
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-}
-
-// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
-// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
-impl AssocConsts for u64 {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    // even if this sets an unfrozen variant, the lint ignores it.
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-}
-
-// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
-// here are values; and I think substituted generics at definitions won't appear in MIR.
-trait AssocTypes {
-    type ToBeUnfrozen;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-}
-
-impl AssocTypes for u64 {
-    type ToBeUnfrozen = AtomicUsize;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-    //~^ declare_interior_mutable_const
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
-}
-
-// Use raw pointers since direct generics have a false negative at the type level.
-enum BothOfCellAndGeneric<T> {
-    Unfrozen(Cell<*const T>),
-    Generic(*const T),
-    Frozen(usize),
-}
-
-impl<T> BothOfCellAndGeneric<T> {
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    //~^ declare_interior_mutable_const
-
-    // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
-    const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
-
-    const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
-
-    // This is what is likely to be a false negative when one tries to fix
-    // the `GENERIC_VARIANT` false positive.
-    const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-    //~^ declare_interior_mutable_const
-}
-
-// associated types here is basically the same as the one above.
-trait BothOfCellAndGenericWithAssocType {
-    type AssocType;
-
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-        //~^ declare_interior_mutable_const
-        BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
-    const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr
deleted file mode 100644
index 32839d14f0e..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:12:1
-   |
-LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:24:1
-   |
-LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:47:1
-   |
-LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
-LL | |
-LL | |     outer: NestedOuter::NestedInner(NestedInner {
-LL | |         inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
-LL | |     }),
-LL | | };
-   | |__^
-   |
-   = help: consider making this a static item
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:62:5
-   |
-LL |     const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:64:5
-   |
-LL |     const TO_BE_FROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:68:5
-   |
-LL |     const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:95:5
-   |
-LL |     const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:108:5
-   |
-LL |     const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:112:5
-   |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:119:5
-   |
-LL |     const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:127:5
-   |
-LL | /     const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-LL | |
-LL | |         BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   | |____________________________________________________________________^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:130:5
-   |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs
deleted file mode 100644
index 7ce04a3f2c3..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::fmt::Display;
-use std::ptr;
-use std::sync::Once;
-use std::sync::atomic::AtomicUsize;
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-//~^ declare_interior_mutable_const
-const CELL: Cell<usize> = Cell::new(6);
-//~^ declare_interior_mutable_const
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-//~^ declare_interior_mutable_const
-
-macro_rules! declare_const {
-    ($name:ident: $ty:ty = $e:expr) => {
-        const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
-    };
-}
-declare_const!(_ONCE: Once = Once::new());
-
-// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
-
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-// note: a const item of Cow is used in the `postgres` package.
-
-const NO_ANN: &dyn Display = &70;
-
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-// there should be no lints on the line above line
-
-mod issue_8493 {
-    use std::cell::Cell;
-
-    thread_local! {
-        static _BAR: Cell<i32> = const { Cell::new(0) };
-    }
-
-    macro_rules! issue_8493 {
-        () => {
-            const _BAZ: Cell<usize> = Cell::new(0);
-            //~^ declare_interior_mutable_const
-            static _FOOBAR: () = {
-                thread_local! {
-                    static _VAR: Cell<i32> = const { Cell::new(0) };
-                }
-            };
-        };
-    }
-
-    issue_8493!();
-}
-
-#[repr(C, align(8))]
-struct NoAtomic(usize);
-#[repr(C, align(8))]
-struct WithAtomic(AtomicUsize);
-
-const fn with_non_null() -> *const WithAtomic {
-    const NO_ATOMIC: NoAtomic = NoAtomic(0);
-    (&NO_ATOMIC as *const NoAtomic).cast()
-}
-const WITH_ATOMIC: *const WithAtomic = with_non_null();
-
-struct Generic<T>(T);
-impl<T> Generic<T> {
-    const RAW_POINTER: *const Cell<T> = ptr::null();
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr
deleted file mode 100644
index 09299b29041..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:10:1
-   |
-LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this a static item
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:12:1
-   |
-LL | const CELL: Cell<usize> = Cell::new(6);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:14:1
-   |
-LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this a static item
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:19:9
-   |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | declare_const!(_ONCE: Once = Once::new());
-   | ----------------------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:47:13
-   |
-LL |             const _BAZ: Cell<usize> = Cell::new(0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     issue_8493!();
-   |     ------------- in this macro invocation
-   |
-   = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 5 previous errors
-
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
deleted file mode 100644
index d3139be6859..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-macro_rules! declare_const {
-    ($name:ident: $ty:ty = $e:expr) => {
-        const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
-    };
-}
-
-// a constant whose type is a concrete type should be linted at the definition site.
-trait ConcreteTypes {
-    const ATOMIC: AtomicUsize;
-    //~^ declare_interior_mutable_const
-    const INTEGER: u64;
-    const STRING: String;
-    declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
-}
-
-impl ConcreteTypes for u64 {
-    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
-    const INTEGER: u64 = 10;
-    const STRING: String = String::new();
-}
-
-// a helper trait used below
-trait ConstDefault {
-    const DEFAULT: Self;
-}
-
-// a constant whose type is a generic type should be linted at the implementation site.
-trait GenericTypes<T, U> {
-    const TO_REMAIN_GENERIC: T;
-    const TO_BE_CONCRETE: U;
-
-    const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
-    declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
-}
-
-impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
-    const TO_REMAIN_GENERIC: T = T::DEFAULT;
-    const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-    //~^ declare_interior_mutable_const
-}
-
-// a helper type used below
-struct Wrapper<T>(T);
-
-// a constant whose type is an associated type should be linted at the implementation site, too.
-trait AssocTypes {
-    type ToBeFrozen;
-    type ToBeUnfrozen;
-    type ToBeGenericParam;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
-    // to ensure it can handle things when a generic type remains after normalization.
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
-}
-
-impl<T: ConstDefault> AssocTypes for Vec<T> {
-    type ToBeFrozen = u16;
-    type ToBeUnfrozen = AtomicUsize;
-    type ToBeGenericParam = T;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen = 12;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-    //~^ declare_interior_mutable_const
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
-}
-
-// a helper trait used below
-trait AssocTypesHelper {
-    type NotToBeBounded;
-    type ToBeBounded;
-
-    const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
-}
-
-// a constant whose type is an assoc type originated from a generic param bounded at the definition
-// site should be linted at there.
-trait AssocTypesFromGenericParam<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded;
-    const BOUNDED: T::ToBeBounded;
-    //~^ declare_interior_mutable_const
-}
-
-impl<T> AssocTypesFromGenericParam<T> for u64
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    // an associated type could remain unknown in a trait impl.
-    const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
-}
-
-// a constant whose type is `Self` should be linted at the implementation site as well.
-// (`Option` requires `Sized` bound.)
-trait SelfType: Sized {
-    const SELF: Self;
-    // this was the one in the original issue (#5050).
-    const WRAPPED_SELF: Option<Self>;
-}
-
-impl SelfType for u64 {
-    const SELF: Self = 16;
-    const WRAPPED_SELF: Option<Self> = Some(20);
-}
-
-impl SelfType for AtomicUsize {
-    // this (interior mutable `Self` const) exists in `parking_lot`.
-    // `const_trait_impl` will replace it in the future, hopefully.
-    const SELF: Self = AtomicUsize::new(17);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-    //~^ declare_interior_mutable_const
-}
-
-// Even though a constant contains a generic type, if it also have an interior mutable type,
-// it should be linted at the definition site.
-trait BothOfCellAndGeneric<T> {
-    const DIRECT: Cell<T>;
-    //~^ declare_interior_mutable_const
-    const INDIRECT: Cell<*const T>;
-    //~^ declare_interior_mutable_const
-}
-
-impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
-    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-    //~^ declare_interior_mutable_const
-    const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
-}
-
-struct Local<T>(T);
-
-// a constant in an inherent impl are essentially the same as a normal const item
-// except there can be a generic or associated type.
-impl<T> Local<T>
-where
-    T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-    //~^ declare_interior_mutable_const
-    const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-
-    const GENERIC_TYPE: T = T::DEFAULT;
-
-    const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-    //~^ declare_interior_mutable_const
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
deleted file mode 100644
index b03dd7a0840..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
+++ /dev/null
@@ -1,88 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:16:5
-   |
-LL |     const ATOMIC: AtomicUsize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:9:9
-   |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
-   |     ---------------------------------------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:45:5
-   |
-LL |     const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:71:5
-   |
-LL |     const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:73:5
-   |
-LL |     const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:93:5
-   |
-LL |     const BOUNDED: T::ToBeBounded;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:122:5
-   |
-LL |     const SELF: Self = AtomicUsize::new(17);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:124:5
-   |
-LL |     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:131:5
-   |
-LL |     const DIRECT: Cell<T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:133:5
-   |
-LL |     const INDIRECT: Cell<*const T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:138:5
-   |
-LL |     const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:151:5
-   |
-LL |     const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:158:5
-   |
-LL |     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 13 previous errors
-
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index 2787f6406fe..6b69bdd29ce 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -2,20 +2,20 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
-#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
+#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
 #![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice`
-#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
-#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
-#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items`
 #![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute`
-#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
+#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
+#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
+#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
+#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
+#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
+#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
 #![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization`
+#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
 #![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect`
-#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
-#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
-#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
 #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
-#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
-#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index 604732405c3..07e59d33d60 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -1,8 +1,8 @@
-error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
+error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
   --> tests/ui/deprecated.rs:5:9
    |
-LL | #![warn(clippy::should_assert_eq)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::assign_ops)]
+   |         ^^^^^^^^^^^^^^^^^^
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
@@ -13,83 +13,83 @@ error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slic
 LL | #![warn(clippy::extend_from_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
+error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`
   --> tests/ui/deprecated.rs:7:9
    |
-LL | #![warn(clippy::range_step_by_zero)]
+LL | #![warn(clippy::match_on_vec_items)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
+error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
   --> tests/ui/deprecated.rs:8:9
    |
-LL | #![warn(clippy::unstable_as_slice)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::misaligned_transmute)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
+error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case
   --> tests/ui/deprecated.rs:9:9
    |
-LL | #![warn(clippy::unstable_as_mut_slice)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::option_map_or_err_ok)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
+error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
   --> tests/ui/deprecated.rs:10:9
    |
-LL | #![warn(clippy::misaligned_transmute)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::pub_enum_variant_names)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
+error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
   --> tests/ui/deprecated.rs:11:9
    |
-LL | #![warn(clippy::assign_ops)]
-   |         ^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::range_step_by_zero)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
+error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
   --> tests/ui/deprecated.rs:12:9
    |
-LL | #![warn(clippy::unsafe_vector_initialization)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::regex_macro)]
+   |         ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
+error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
   --> tests/ui/deprecated.rs:13:9
    |
-LL | #![warn(clippy::unused_collect)]
+LL | #![warn(clippy::replace_consts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
+error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
   --> tests/ui/deprecated.rs:14:9
    |
-LL | #![warn(clippy::replace_consts)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::should_assert_eq)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
+error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
   --> tests/ui/deprecated.rs:15:9
    |
-LL | #![warn(clippy::regex_macro)]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unsafe_vector_initialization)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
   --> tests/ui/deprecated.rs:16:9
    |
-LL | #![warn(clippy::pub_enum_variant_names)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_mut_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
   --> tests/ui/deprecated.rs:17:9
    |
-LL | #![warn(clippy::wrong_pub_self_convention)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case
+error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
   --> tests/ui/deprecated.rs:18:9
    |
-LL | #![warn(clippy::option_map_or_err_ok)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unused_collect)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`
+error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
   --> tests/ui/deprecated.rs:19:9
    |
-LL | #![warn(clippy::match_on_vec_items)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::wrong_pub_self_convention)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
index e9218bbb409..73f62ac1246 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: requires manual changes
 #![warn(clippy::double_ended_iterator_last)]
 
 // Should not be linted because applying the lint would move the original iterator. This can only be
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
index 874f5d22075..3ca91d6f182 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.rs
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -21,7 +21,7 @@ fn foo() {}
 fn bar() {}
 
 // No warning:
-#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))]
+#[rustc_on_unimplemented(on(Self = "&str", label = "`a"), on(Self = "alloc::string::String", label = "a"))]
 trait Abc {}
 
 #[proc_macro_attr::duplicated_attr()] // Should not warn!
diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
index b1600862a8f..419cf2354f8 100644
--- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
+++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
@@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint
 struct MySingleTupleStruct(usize); // should not trigger lint
 struct MyUnitLikeStruct; // should not trigger lint
 
+macro_rules! empty_struct {
+    ($s:ident) => {
+        struct $s {}
+    };
+}
+
+empty_struct!(FromMacro);
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
index 1f69c4be9ec..90c415c1220 100644
--- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
@@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint
 struct MySingleTupleStruct(usize); // should not trigger lint
 struct MyUnitLikeStruct; // should not trigger lint
 
+macro_rules! empty_struct {
+    ($s:ident) => {
+        struct $s {}
+    };
+}
+
+empty_struct!(FromMacro);
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.rs b/src/tools/clippy/tests/ui/entry_unfixable.rs
index dbdacf95056..c4c05557208 100644
--- a/src/tools/clippy/tests/ui/entry_unfixable.rs
+++ b/src/tools/clippy/tests/ui/entry_unfixable.rs
@@ -1,6 +1,5 @@
-#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
+#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
 #![warn(clippy::map_entry)]
-//@no-rustfix
 
 use std::collections::HashMap;
 use std::hash::Hash;
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.stderr b/src/tools/clippy/tests/ui/entry_unfixable.stderr
index 9f9956d351b..0197d2ab4cf 100644
--- a/src/tools/clippy/tests/ui/entry_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/entry_unfixable.stderr
@@ -1,5 +1,5 @@
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:28:13
+  --> tests/ui/entry_unfixable.rs:27:13
    |
 LL | /             if !self.values.contains_key(&name) {
 LL | |
@@ -14,7 +14,7 @@ LL | |             }
    = help: to override `-D warnings` add `#[allow(clippy::map_entry)]`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:43:5
+  --> tests/ui/entry_unfixable.rs:42:5
    |
 LL | /     if hm.contains_key(&key) {
 LL | |
@@ -26,7 +26,7 @@ LL | |     }
    | |_____^
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:81:13
+  --> tests/ui/entry_unfixable.rs:80:13
    |
 LL | /             if self.globals.contains_key(&name) {
 LL | |
diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed
index 99d09774d16..8a8c2e1939c 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.fixed
+++ b/src/tools/clippy/tests/ui/excessive_precision.fixed
@@ -79,6 +79,9 @@ fn main() {
     // issue #2840
     let num = 0.000_000_000_01e-10f64;
 
+    // issue #6341
+    let exponential: f64 = 4.886506780521244E-03;
+
     // issue #7744
     let _ = 2.225_073_858_507_201e-308_f64;
     //~^ excessive_precision
diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs
index a542fb2e7e3..5dcf55cb927 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.rs
+++ b/src/tools/clippy/tests/ui/excessive_precision.rs
@@ -79,6 +79,9 @@ fn main() {
     // issue #2840
     let num = 0.000_000_000_01e-10f64;
 
+    // issue #6341
+    let exponential: f64 = 4.886506780521244E-03;
+
     // issue #7744
     let _ = 2.225_073_858_507_201_1e-308_f64;
     //~^ excessive_precision
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
index 934a367e106..f5eeadf0c8c 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.stderr
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -157,7 +157,7 @@ LL +     let bad_bige32: f32 = 1.123_456_8E-10;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:83:13
+  --> tests/ui/excessive_precision.rs:86:13
    |
 LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL +     let _ = 2.225_073_858_507_201e-308_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:87:13
+  --> tests/ui/excessive_precision.rs:90:13
    |
 LL |     let _ = 1.000_000_000_000_001e-324_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL +     let _ = 0_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:98:20
+  --> tests/ui/excessive_precision.rs:101:20
    |
 LL |     const _: f64 = 3.0000000000000000e+00;
    |                    ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index 8340d99ace2..13934785d7b 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::explicit_counter_loop)]
 #![allow(clippy::uninlined_format_args, clippy::useless_vec)]
-//@no-rustfix
+//@no-rustfix: suggestion does not remove the `+= 1`
 fn main() {
     let mut vec = vec![1, 2, 3, 4];
     let mut _index = 0;
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
index 0d1a5f80f3d..619329a6ade 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
@@ -8,7 +8,8 @@
     clippy::needless_borrow,
     clippy::no_effect,
     clippy::uninlined_format_args,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::deref_addrof
 )]
 
 use std::ops::{Deref, DerefMut};
@@ -87,9 +88,6 @@ fn main() {
     let b = &*opt_a.unwrap();
     //~^ explicit_deref_methods
 
-    // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified
-    // syntax
-
     Aaa::deref(&Aaa);
     Aaa::deref_mut(&mut Aaa);
     <Aaa as Deref>::deref(&Aaa);
@@ -139,4 +137,9 @@ fn main() {
     let no_lint = NoLint(42);
     let b = no_lint.deref();
     let b = no_lint.deref_mut();
+
+    let _ = &*&"foo"; //~ explicit_deref_methods
+    let mut x = String::new();
+    let _ = &&mut **&mut x; //~ explicit_deref_methods
+    let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods
 }
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
index 8d4a899cd26..9f2d513283c 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
@@ -8,7 +8,8 @@
     clippy::needless_borrow,
     clippy::no_effect,
     clippy::uninlined_format_args,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::deref_addrof
 )]
 
 use std::ops::{Deref, DerefMut};
@@ -87,9 +88,6 @@ fn main() {
     let b = opt_a.unwrap().deref();
     //~^ explicit_deref_methods
 
-    // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified
-    // syntax
-
     Aaa::deref(&Aaa);
     Aaa::deref_mut(&mut Aaa);
     <Aaa as Deref>::deref(&Aaa);
@@ -139,4 +137,9 @@ fn main() {
     let no_lint = NoLint(42);
     let b = no_lint.deref();
     let b = no_lint.deref_mut();
+
+    let _ = &Deref::deref(&"foo"); //~ explicit_deref_methods
+    let mut x = String::new();
+    let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods
+    let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods
 }
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
index 2ca376cba00..a81e2f60317 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
@@ -1,5 +1,5 @@
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:54:19
+  --> tests/ui/explicit_deref_methods.rs:55:19
    |
 LL |     let b: &str = a.deref();
    |                   ^^^^^^^^^ help: try: `&*a`
@@ -8,70 +8,88 @@ LL |     let b: &str = a.deref();
    = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]`
 
 error: explicit `deref_mut` method call
-  --> tests/ui/explicit_deref_methods.rs:57:23
+  --> tests/ui/explicit_deref_methods.rs:58:23
    |
 LL |     let b: &mut str = a.deref_mut();
    |                       ^^^^^^^^^^^^^ help: try: `&mut **a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:61:39
+  --> tests/ui/explicit_deref_methods.rs:62:39
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                       ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:61:50
+  --> tests/ui/explicit_deref_methods.rs:62:50
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                                  ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:65:20
+  --> tests/ui/explicit_deref_methods.rs:66:20
    |
 LL |     println!("{}", a.deref());
    |                    ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:69:11
+  --> tests/ui/explicit_deref_methods.rs:70:11
    |
 LL |     match a.deref() {
    |           ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:74:28
+  --> tests/ui/explicit_deref_methods.rs:75:28
    |
 LL |     let b: String = concat(a.deref());
    |                            ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:77:13
+  --> tests/ui/explicit_deref_methods.rs:78:13
    |
 LL |     let b = just_return(a).deref();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:80:28
+  --> tests/ui/explicit_deref_methods.rs:81:28
    |
 LL |     let b: String = concat(just_return(a).deref());
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:83:19
+  --> tests/ui/explicit_deref_methods.rs:84:19
    |
 LL |     let b: &str = a.deref().deref();
    |                   ^^^^^^^^^^^^^^^^^ help: try: `&**a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:87:13
+  --> tests/ui/explicit_deref_methods.rs:88:13
    |
 LL |     let b = opt_a.unwrap().deref();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:125:31
+  --> tests/ui/explicit_deref_methods.rs:123:31
    |
 LL |     let b: &str = expr_deref!(a.deref());
    |                               ^^^^^^^^^ help: try: `&*a`
 
-error: aborting due to 12 previous errors
+error: explicit `deref` method call
+  --> tests/ui/explicit_deref_methods.rs:141:14
+   |
+LL |     let _ = &Deref::deref(&"foo");
+   |              ^^^^^^^^^^^^^^^^^^^^ help: try: `*&"foo"`
+
+error: explicit `deref_mut` method call
+  --> tests/ui/explicit_deref_methods.rs:143:14
+   |
+LL |     let _ = &DerefMut::deref_mut(&mut x);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut **&mut x`
+
+error: explicit `deref_mut` method call
+  --> tests/ui/explicit_deref_methods.rs:144:14
+   |
+LL |     let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut ***(&mut &mut x)`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
index 2b68906ae39..c1b3c478eeb 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
@@ -73,3 +73,16 @@ fn main() {
 
     for _ in S.into_iter::<u32>() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (into_iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]) {}
+    //~^ explicit_into_iter_loop
+
+    for _ in mac!(into_iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
index ca335b62d90..581e0dadcec 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
@@ -73,3 +73,16 @@ fn main() {
 
     for _ in S.into_iter::<u32>() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (into_iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]).into_iter() {}
+    //~^ explicit_into_iter_loop
+
+    for _ in mac!(into_iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
index 1c3156755d4..26fb11e0048 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
@@ -37,5 +37,11 @@ error: it is more concise to loop over containers instead of using explicit iter
 LL |     for _ in mr.into_iter() {}
    |              ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr`
 
-error: aborting due to 6 previous errors
+error: it is more concise to loop over containers instead of using explicit iteration methods
+  --> tests/ui/explicit_into_iter_loop.rs:84:14
+   |
+LL |     for _ in dbg!([1, 2]).into_iter() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `dbg!([1, 2])`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
index cd0898dfc36..f246ec61800 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
@@ -183,3 +183,16 @@ pub fn issue_13184() {
     let rvalues = &values;
     for _ in rvalues.iter() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in &dbg!([1, 2]) {}
+    //~^ explicit_iter_loop
+
+    for _ in mac!(iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
index 02405280ce4..35f4fb7097d 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
@@ -183,3 +183,16 @@ pub fn issue_13184() {
     let rvalues = &values;
     for _ in rvalues.iter() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]).iter() {}
+    //~^ explicit_iter_loop
+
+    for _ in mac!(iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
index 3816bb4db98..575dbe7813d 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
@@ -112,5 +112,11 @@ error: it is more concise to loop over references to containers instead of using
 LL |     for _ in r.iter() {}
    |              ^^^^^^^^ help: to write this more concisely, try: `r`
 
-error: aborting due to 18 previous errors
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> tests/ui/explicit_iter_loop.rs:194:14
+   |
+LL |     for _ in dbg!([1, 2]).iter() {}
+   |              ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&dbg!([1, 2])`
+
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
index 68294292502..5d29e0317bb 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
@@ -1,6 +1,5 @@
-#![allow(clippy::question_mark, unused)]
+#![allow(clippy::question_mark)]
 #![warn(clippy::filter_map_bool_then)]
-//@no-rustfix
 
 fn issue11617() {
     let mut x: Vec<usize> = vec![0; 10];
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
index 2025958136b..2990423973e 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
@@ -1,5 +1,5 @@
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:7:48
+  --> tests/ui/filter_map_bool_then_unfixable.rs:6:48
    |
 LL |       let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| {
    |  ________________________________________________^
@@ -16,7 +16,7 @@ LL | |     });
    = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]`
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:23:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:22:26
    |
 LL |         let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |         let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:27:14
+  --> tests/ui/filter_map_bool_then_unfixable.rs:26:14
    |
 LL |             .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(())));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |             .filter_map(|&x| if let Some(x) = x { x } else { return None }.
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:29:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:28:26
    |
 LL |           let _ = x.iter().filter_map(|&x| {
    |  __________________________^
@@ -47,7 +47,7 @@ LL | |         });
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:47:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:46:26
    |
 LL |           let _ = x.iter().filter_map(|&x| {
    |  __________________________^
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index ebc3acb1b77..7067434953d 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -6,19 +6,25 @@ fn ifs_same_cond() {
     let b = false;
 
     if b {
+        //~^ ifs_same_cond
     } else if b {
+    }
+
+    if b {
         //~^ ifs_same_cond
+    } else if b {
+    } else if b {
     }
 
     if a == 1 {
-    } else if a == 1 {
         //~^ ifs_same_cond
+    } else if a == 1 {
     }
 
     if 2 * a == 1 {
+        //~^ ifs_same_cond
     } else if 2 * a == 2 {
     } else if 2 * a == 1 {
-        //~^ ifs_same_cond
     } else if a == 1 {
     }
 
@@ -50,8 +56,8 @@ fn ifs_same_cond() {
 fn issue10272() {
     let a = String::from("ha");
     if a.contains("ah") {
-    } else if a.contains("ah") {
         //~^ ifs_same_cond
+    } else if a.contains("ah") {
 
         // Trigger this lint
     } else if a.contains("ha") {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index df21e6f1b82..7acbc1a6399 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -1,52 +1,52 @@
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:9:15
-   |
-LL |     } else if b {
-   |               ^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui/ifs_same_cond.rs:8:8
    |
 LL |     if b {
    |        ^
+LL |
+LL |     } else if b {
+   |               ^
+   |
    = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]`
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:14:15
-   |
-LL |     } else if a == 1 {
-   |               ^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui/ifs_same_cond.rs:13:8
    |
+LL |     if b {
+   |        ^
+LL |
+LL |     } else if b {
+   |               ^
+LL |     } else if b {
+   |               ^
+
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:19:8
+   |
 LL |     if a == 1 {
    |        ^^^^^^
+LL |
+LL |     } else if a == 1 {
+   |               ^^^^^^
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:20:15
-   |
-LL |     } else if 2 * a == 1 {
-   |               ^^^^^^^^^^
-   |
-note: same as this
-  --> tests/ui/ifs_same_cond.rs:18:8
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:24:8
    |
 LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
+...
+LL |     } else if 2 * a == 1 {
+   |               ^^^^^^^^^^
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:53:15
-   |
-LL |     } else if a.contains("ah") {
-   |               ^^^^^^^^^^^^^^^^
-   |
-note: same as this
-  --> tests/ui/ifs_same_cond.rs:52:8
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:58:8
    |
 LL |     if a.contains("ah") {
    |        ^^^^^^^^^^^^^^^^
+LL |
+LL |     } else if a.contains("ah") {
+   |               ^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
index 2039f6339a8..72e3e068c9c 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.rs
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -1,7 +1,7 @@
 #![allow(unused)]
 #![warn(clippy::impl_trait_in_params)]
 
-//@no-rustfix
+//@no-rustfix: has placeholders
 pub trait Trait {}
 pub trait AnotherTrait<T> {}
 
diff --git a/src/tools/clippy/tests/ui/infinite_loop.rs b/src/tools/clippy/tests/ui/infinite_loop.rs
index 4a0968918bf..8ff7f3b0c18 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.rs
+++ b/src/tools/clippy/tests/ui/infinite_loop.rs
@@ -1,5 +1,3 @@
-//@no-rustfix
-
 fn fn_val(i: i32) -> i32 {
     unimplemented!()
 }
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
index 7ba1374d64f..04da9776c30 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -1,5 +1,5 @@
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:22:11
+  --> tests/ui/infinite_loop.rs:20:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
@@ -8,7 +8,7 @@ LL |     while y < 10 {
    = note: `#[deny(clippy::while_immutable_condition)]` on by default
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:29:11
+  --> tests/ui/infinite_loop.rs:27:11
    |
 LL |     while y < 10 && x < 3 {
    |           ^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     while y < 10 && x < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:38:11
+  --> tests/ui/infinite_loop.rs:36:11
    |
 LL |     while !cond {
    |           ^^^^^
@@ -24,7 +24,7 @@ LL |     while !cond {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:84:11
+  --> tests/ui/infinite_loop.rs:82:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -32,7 +32,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:91:11
+  --> tests/ui/infinite_loop.rs:89:11
    |
 LL |     while i < 3 && j > 0 {
    |           ^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     while i < 3 && j > 0 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:97:11
+  --> tests/ui/infinite_loop.rs:95:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -48,7 +48,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:114:11
+  --> tests/ui/infinite_loop.rs:112:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -56,7 +56,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:121:11
+  --> tests/ui/infinite_loop.rs:119:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -64,7 +64,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:189:15
+  --> tests/ui/infinite_loop.rs:187:15
    |
 LL |         while self.count < n {
    |               ^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |         while self.count < n {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:199:11
+  --> tests/ui/infinite_loop.rs:197:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
@@ -82,7 +82,7 @@ LL |     while y < 10 {
    = help: rewrite it as `if cond { loop { } }`
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:208:11
+  --> tests/ui/infinite_loop.rs:206:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs
index eaa8d008806..fcd1f795fff 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.rs
+++ b/src/tools/clippy/tests/ui/infinite_loops.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: multiple suggestions add `-> !` to the same fn
 //@aux-build:proc_macros.rs
 
 #![allow(clippy::never_loop)]
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
index 45e34b3930a..f0b86e5620e 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: suggestions reference out of scope lifetimes/types
 //@aux-build:proc_macros.rs
 #![warn(clippy::into_iter_without_iter)]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs
index 32711c7ef62..8e62ed963b9 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.rs
+++ b/src/tools/clippy/tests/ui/iter_next_loop.rs
@@ -15,3 +15,16 @@ fn main() {
     let u = Unrelated(&[0]);
     for _v in u.next() {} // no error
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (next $e:expr) => {
+            $e.iter().next()
+        };
+    }
+
+    for _ in dbg!([1, 2].iter()).next() {}
+    //~^ iter_next_loop
+
+    for _ in mac!(next [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.stderr b/src/tools/clippy/tests/ui/iter_next_loop.stderr
index acc55031c3b..c076e86db93 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.stderr
+++ b/src/tools/clippy/tests/ui/iter_next_loop.stderr
@@ -7,5 +7,11 @@ LL |     for _ in x.iter().next() {}
    = note: `-D clippy::iter-next-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]`
 
-error: aborting due to 1 previous error
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
+  --> tests/ui/iter_next_loop.rs:26:14
+   |
+LL |     for _ in dbg!([1, 2].iter()).next() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
index b34e4ad7824..6458b1342dc 100644
--- a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
@@ -1,5 +1,3 @@
-//@no-rustfix
-
 #![deny(clippy::iter_out_of_bounds)]
 #![allow(clippy::useless_vec)]
 
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
index 19ac60b9d0a..1b3a99e1e94 100644
--- a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
@@ -1,18 +1,18 @@
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:12:14
+  --> tests/ui/iter_out_of_bounds.rs:10:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this operation is useless and will create an empty iterator
 note: the lint level is defined here
-  --> tests/ui/iter_out_of_bounds.rs:3:9
+  --> tests/ui/iter_out_of_bounds.rs:1:9
    |
 LL | #![deny(clippy::iter_out_of_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:17:19
+  --> tests/ui/iter_out_of_bounds.rs:15:19
    |
 LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:24:14
+  --> tests/ui/iter_out_of_bounds.rs:22:14
    |
 LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:27:14
+  --> tests/ui/iter_out_of_bounds.rs:25:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     for _ in [1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:30:14
+  --> tests/ui/iter_out_of_bounds.rs:28:14
    |
 LL |     for _ in [1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     for _ in [1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:36:14
+  --> tests/ui/iter_out_of_bounds.rs:34:14
    |
 LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:39:14
+  --> tests/ui/iter_out_of_bounds.rs:37:14
    |
 LL |     for _ in vec![1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     for _ in vec![1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:43:14
+  --> tests/ui/iter_out_of_bounds.rs:41:14
    |
 LL |     for _ in x.iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     for _ in x.iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:47:14
+  --> tests/ui/iter_out_of_bounds.rs:45:14
    |
 LL |     for _ in x.iter().skip(n) {}
    |              ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     for _ in x.iter().skip(n) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:52:14
+  --> tests/ui/iter_out_of_bounds.rs:50:14
    |
 LL |     for _ in empty().skip(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     for _ in empty().skip(1) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:55:14
+  --> tests/ui/iter_out_of_bounds.rs:53:14
    |
 LL |     for _ in empty().take(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |     for _ in empty().take(1) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:58:14
+  --> tests/ui/iter_out_of_bounds.rs:56:14
    |
 LL |     for _ in std::iter::once(1).skip(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     for _ in std::iter::once(1).skip(2) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:61:14
+  --> tests/ui/iter_out_of_bounds.rs:59:14
    |
 LL |     for _ in std::iter::once(1).take(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL |     for _ in std::iter::once(1).take(2) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:64:14
+  --> tests/ui/iter_out_of_bounds.rs:62:14
    |
 LL |     for x in [].iter().take(1) {
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed
index ec87fe217ae..9b768dbad70 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.fixed
+++ b/src/tools/clippy/tests/ui/manual_inspect.fixed
@@ -107,7 +107,7 @@ fn main() {
             let _ = || {
                 let _x = x;
             };
-            return ;
+            return;
         }
         println!("test");
     });
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index eb98f9f5995..78b085fdfca 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -98,7 +98,7 @@ LL |         if x.is_empty() {
 LL |             let _ = || {
 LL ~                 let _x = x;
 LL |             };
-LL ~             return ;
+LL ~             return;
 LL |         }
 LL ~         println!("test");
    |
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
index 294d1e1506d..090f0fd30c5 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
@@ -60,7 +60,26 @@ fn main() {
     let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
 }
 
-const fn _const(s_i32: &[i32]) {
-    // True negative:
-    let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
+#[clippy::msrv = "1.85"]
+const fn const_ok(s_i32: &[i32]) {
+    let _ = std::mem::size_of_val(s_i32);
+    //~^ manual_slice_size_calculation
+}
+
+#[clippy::msrv = "1.84"]
+const fn const_before_msrv(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+}
+
+fn issue_14802() {
+    struct IcedSlice {
+        dst: [u8],
+    }
+
+    impl IcedSlice {
+        fn get_len(&self) -> usize {
+            std::mem::size_of_val(&self.dst)
+            //~^ manual_slice_size_calculation
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
index ae522566313..3c19a0eb5ce 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
@@ -60,7 +60,26 @@ fn main() {
     let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
 }
 
-const fn _const(s_i32: &[i32]) {
-    // True negative:
-    let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
+#[clippy::msrv = "1.85"]
+const fn const_ok(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+    //~^ manual_slice_size_calculation
+}
+
+#[clippy::msrv = "1.84"]
+const fn const_before_msrv(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+}
+
+fn issue_14802() {
+    struct IcedSlice {
+        dst: [u8],
+    }
+
+    impl IcedSlice {
+        fn get_len(&self) -> usize {
+            self.dst.len() * size_of::<u8>()
+            //~^ manual_slice_size_calculation
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
index f07e97a1c86..8e9b49e4bf2 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
@@ -55,5 +55,17 @@ error: manual slice size calculation
 LL |     let _ = external!(&[1u64][..]).len() * size_of::<u64>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))`
 
-error: aborting due to 9 previous errors
+error: manual slice size calculation
+  --> tests/ui/manual_slice_size_calculation.rs:65:13
+   |
+LL |     let _ = s_i32.len() * size_of::<i32>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
+
+error: manual slice size calculation
+  --> tests/ui/manual_slice_size_calculation.rs:81:13
+   |
+LL |             self.dst.len() * size_of::<u8>()
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed
new file mode 100644
index 00000000000..31684a5759f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms.fixed
@@ -0,0 +1,142 @@
+#![allow(clippy::manual_range_patterns)]
+#![warn(clippy::match_same_arms)]
+
+pub enum Abc {
+    A,
+    B,
+    C,
+}
+
+fn match_same_arms() {
+    let _ = match Abc::A {
+        Abc::B => 1,
+        _ => 0,
+        //~^ match_same_arms
+    };
+
+    match 0 {
+        1 => 'a',
+        _ => 'b',
+        //~^ match_same_arms
+    };
+
+    match (1, 2, 3) {
+        (1, .., 3) | (.., 3) => 42,
+        //~^ match_same_arms
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        //~^ match_same_arms
+        42 | 51 => 1,
+        41 | 52 => 2,
+        //~^ match_same_arms
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        //~^ match_same_arms
+        1 | 2 | 3 => 2,
+        4 => 3,
+        _ => 0,
+    };
+}
+
+mod issue4244 {
+    #[derive(PartialEq, PartialOrd, Eq, Ord)]
+    pub enum CommandInfo {
+        BuiltIn { name: String, about: Option<String> },
+        External { name: String, path: std::path::PathBuf },
+    }
+
+    impl CommandInfo {
+        pub fn name(&self) -> String {
+            match self {
+                //~^ match_same_arms
+                CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(),
+            }
+        }
+    }
+}
+
+macro_rules! m {
+    (foo) => {};
+    (bar) => {};
+}
+macro_rules! foo {
+    () => {
+        1
+    };
+}
+macro_rules! bar {
+    () => {
+        1
+    };
+}
+
+fn main() {
+    let x = 0;
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            x
+        },
+        1 => {
+            m!(bar);
+            x
+        },
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            0
+        },
+        1 => {
+            m!(bar);
+            0
+        },
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => {
+            let mut x = 0;
+            #[cfg(not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        1 => {
+            let mut x = 0;
+            #[cfg(also_not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(also_not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        _ => 0,
+    };
+
+    let _ = match 0 {
+        0 => foo!(),
+        1 => bar!(),
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => cfg!(not_enabled),
+        1 => cfg!(also_not_enabled),
+        _ => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs
index 55441948e91..39bee01bac2 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms.rs
@@ -1,4 +1,4 @@
-//@no-rustfix: overlapping suggestions
+#![allow(clippy::manual_range_patterns)]
 #![warn(clippy::match_same_arms)]
 
 pub enum Abc {
@@ -10,9 +10,17 @@ pub enum Abc {
 fn match_same_arms() {
     let _ = match Abc::A {
         Abc::A => 0,
-        //~^ match_same_arms
         Abc::B => 1,
         _ => 0,
+        //~^ match_same_arms
+    };
+
+    match 0 {
+        1 => 'a',
+        2 => 'b',
+        3 => 'b',
+        _ => 'b',
+        //~^ match_same_arms
     };
 
     match (1, 2, 3) {
@@ -24,8 +32,8 @@ fn match_same_arms() {
 
     let _ = match 42 {
         42 => 1,
-        51 => 1,
         //~^ match_same_arms
+        51 => 1,
         41 => 2,
         //~^ match_same_arms
         52 => 2,
@@ -34,11 +42,9 @@ fn match_same_arms() {
 
     let _ = match 42 {
         1 => 2,
-        2 => 2,
         //~^ match_same_arms
-        //~| match_same_arms
+        2 => 2,
         3 => 2,
-        //~^ match_same_arms
         4 => 3,
         _ => 0,
     };
@@ -55,8 +61,8 @@ mod issue4244 {
         pub fn name(&self) -> String {
             match self {
                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-                CommandInfo::External { name, .. } => name.to_string(),
                 //~^ match_same_arms
+                CommandInfo::External { name, .. } => name.to_string(),
             }
         }
     }
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
index 3744b83d89c..8aa60f83576 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -1,118 +1,121 @@
-error: this match arm has an identical body to the `_` wildcard arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms.rs:12:9
    |
-LL | /         Abc::A => 0,
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms.rs:15:9
-   |
+LL |         Abc::A => 0,
+   |         ^^^^^^^^^^^
+LL |         Abc::B => 1,
 LL |         _ => 0,
-   |         ^^^^^^
+   |         ^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise remove the non-wildcard arm
+   |
+LL -         Abc::A => 0,
+   |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:19:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:20:9
+   |
+LL |         2 => 'b',
+   |         ^^^^^^^^
+LL |         3 => 'b',
+   |         ^^^^^^^^
+LL |         _ => 'b',
+   |         ^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arms
+   |
+LL -         2 => 'b',
+LL -         3 => 'b',
+LL +         _ => 'b',
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:27:9
    |
 LL |         (1, .., 3) => 42,
    |         ^^^^^^^^^^^^^^^^
+LL |
+LL |         (.., 3) => 42,
+   |         ^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (1, .., 3) | (.., 3) => 42,
 LL |
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:27:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:34:9
    |
+LL |         42 => 1,
+   |         ^^^^^^^
+LL |
 LL |         51 => 1,
    |         ^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         42 => 1,
-LL -         51 => 1,
-LL +         51 | 42 => 1,
+LL ~
+LL ~         42 | 51 => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:29:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:37:9
    |
 LL |         41 => 2,
    |         ^^^^^^^
+LL |
+LL |         52 => 2,
+   |         ^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         41 | 52 => 2,
 LL |
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:37:9
-   |
-LL |         2 => 2,
-   |         ^^^^^^
-   |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
-   |
-LL -         1 => 2,
-LL -         2 => 2,
-LL +         2 | 1 => 2,
-   |
-
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:40:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:44:9
    |
-LL |         3 => 2,
+LL |         1 => 2,
    |         ^^^^^^
-   |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
-   |
-LL ~         2 => 2,
-LL |
 LL |
-LL ~         3 | 1 => 2,
-   |
-
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:37:9
-   |
 LL |         2 => 2,
    |         ^^^^^^
+LL |         3 => 2,
+   |         ^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         2 | 3 => 2,
-LL |
-LL |
 LL ~
+LL ~         1 | 2 | 3 => 2,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:58:17
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:63:17
    |
+LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |                 CommandInfo::External { name, .. } => name.to_string(),
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-LL -                 CommandInfo::External { name, .. } => name.to_string(),
-LL +                 CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(),
+LL ~
+LL ~                 CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(),
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed
index 0d93e2c728d..cb860cef1e6 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed
@@ -14,7 +14,7 @@ fn foo() -> bool {
 
 fn match_same_arms() {
     let _ = match 42 {
-        //~^^^^^^^^^ match_same_arms
+        //~v match_same_arms
         _ => {
             foo();
             let mut a = 42 + [23].len() as i32;
@@ -27,14 +27,14 @@ fn match_same_arms() {
     };
 
     let _ = match 42 {
-        51 | 42 => foo(),
         //~^ match_same_arms
+        42 | 51 => foo(),
         _ => true,
     };
 
     let _ = match Some(42) {
-        None | Some(_) => 24,
         //~^ match_same_arms
+        Some(_) | None => 24,
     };
 
     let _ = match Some(42) {
@@ -55,8 +55,8 @@ fn match_same_arms() {
     };
 
     match (Some(42), Some(42)) {
-        (None, Some(a)) | (Some(a), None) => bar(a),
         //~^ match_same_arms
+        (Some(a), None) | (None, Some(a)) => bar(a),
         _ => (),
     }
 
@@ -69,8 +69,8 @@ fn match_same_arms() {
     };
 
     let _ = match (Some(42), Some(42)) {
-        (None, Some(a)) | (Some(a), None) if a == 42 => a,
         //~^ match_same_arms
+        (Some(a), None) | (None, Some(a)) if a == 42 => a,
         _ => 0,
     };
 
@@ -124,8 +124,8 @@ fn match_same_arms() {
     // False negative #2251.
     match x {
         Ok(_tmp) => println!("ok"),
-        Ok(_) | Ok(3) => println!("ok"),
         //~^ match_same_arms
+        Ok(3) | Ok(_) => println!("ok"),
         Err(_) => {
             unreachable!();
         },
@@ -149,10 +149,10 @@ fn match_same_arms() {
 
     // still lint if the tokens are the same
     match 0 {
-        1 | 0 => {
+        //~^^^ match_same_arms
+        0 | 1 => {
             empty!(0);
         },
-        //~^^^ match_same_arms
         x => {
             empty!(x);
         },
@@ -208,9 +208,9 @@ fn main() {
 
     // Suggest moving `Foo::X(0)` down.
     let _ = match Foo::X(0) {
-        Foo::Y(_) | Foo::Z(0) => 2,
-        Foo::Z(_) | Foo::X(0) => 1,
         //~^ match_same_arms
+        Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::X(0) | Foo::Z(_) => 1,
         _ => 0,
     };
 
@@ -230,10 +230,10 @@ fn main() {
 
     // Lint.
     let _ = match None {
+        //~^ match_same_arms
         Some(Bar { y: 10, z: 0, .. }) => 2,
         None => 50,
-        Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
-        //~^ match_same_arms
+        Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1,
         _ => 200,
     };
 
@@ -246,8 +246,8 @@ fn main() {
     };
 
     let _ = match 0 {
-        1 | 0 => cfg!(not_enable),
         //~^ match_same_arms
+        0 | 1 => cfg!(not_enable),
         _ => false,
     };
 }
@@ -262,9 +262,34 @@ mod with_lifetime {
     impl<'a> MaybeStaticStr<'a> {
         fn get(&self) -> &'a str {
             match *self {
-                MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s,
                 //~^ match_same_arms
+                MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s,
             }
         }
     }
 }
+
+fn lint_levels() {
+    match 1 {
+        0 => "a",
+        1 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 2 {
+        0 => "a",
+        1 | 2 => "b",
+        //~^ match_same_arms
+        #[allow(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 3 {
+        0 => "a",
+        1 | 2 => "b",
+        //~^ match_same_arms
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index b0ebc4784f3..0fd5d76e7d3 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -23,7 +23,7 @@ fn match_same_arms() {
             a = -31 - a;
             a
         },
-        //~^^^^^^^^^ match_same_arms
+        //~v match_same_arms
         _ => {
             foo();
             let mut a = 42 + [23].len() as i32;
@@ -37,15 +37,15 @@ fn match_same_arms() {
 
     let _ = match 42 {
         42 => foo(),
-        51 => foo(),
         //~^ match_same_arms
+        51 => foo(),
         _ => true,
     };
 
     let _ = match Some(42) {
         Some(_) => 24,
-        None => 24,
         //~^ match_same_arms
+        None => 24,
     };
 
     let _ = match Some(42) {
@@ -67,8 +67,8 @@ fn match_same_arms() {
 
     match (Some(42), Some(42)) {
         (Some(a), None) => bar(a),
-        (None, Some(a)) => bar(a),
         //~^ match_same_arms
+        (None, Some(a)) => bar(a),
         _ => (),
     }
 
@@ -82,8 +82,8 @@ fn match_same_arms() {
 
     let _ = match (Some(42), Some(42)) {
         (Some(a), None) if a == 42 => a,
-        (None, Some(a)) if a == 42 => a,
         //~^ match_same_arms
+        (None, Some(a)) if a == 42 => a,
         _ => 0,
     };
 
@@ -140,8 +140,8 @@ fn match_same_arms() {
     match x {
         Ok(_tmp) => println!("ok"),
         Ok(3) => println!("ok"),
-        Ok(_) => println!("ok"),
         //~^ match_same_arms
+        Ok(_) => println!("ok"),
         Err(_) => {
             unreachable!();
         },
@@ -168,10 +168,10 @@ fn match_same_arms() {
         0 => {
             empty!(0);
         },
+        //~^^^ match_same_arms
         1 => {
             empty!(0);
         },
-        //~^^^ match_same_arms
         x => {
             empty!(x);
         },
@@ -229,9 +229,9 @@ fn main() {
     // Suggest moving `Foo::X(0)` down.
     let _ = match Foo::X(0) {
         Foo::X(0) => 1,
+        //~^ match_same_arms
         Foo::Y(_) | Foo::Z(0) => 2,
         Foo::Z(_) => 1,
-        //~^ match_same_arms
         _ => 0,
     };
 
@@ -252,10 +252,10 @@ fn main() {
     // Lint.
     let _ = match None {
         Some(Bar { x: 0, y: 5, .. }) => 1,
+        //~^ match_same_arms
         Some(Bar { y: 10, z: 0, .. }) => 2,
         None => 50,
         Some(Bar { y: 0, x: 5, .. }) => 1,
-        //~^ match_same_arms
         _ => 200,
     };
 
@@ -269,8 +269,8 @@ fn main() {
 
     let _ = match 0 {
         0 => cfg!(not_enable),
-        1 => cfg!(not_enable),
         //~^ match_same_arms
+        1 => cfg!(not_enable),
         _ => false,
     };
 }
@@ -286,9 +286,36 @@ mod with_lifetime {
         fn get(&self) -> &'a str {
             match *self {
                 MaybeStaticStr::Static(s) => s,
-                MaybeStaticStr::Borrowed(s) => s,
                 //~^ match_same_arms
+                MaybeStaticStr::Borrowed(s) => s,
             }
         }
     }
 }
+
+fn lint_levels() {
+    match 1 {
+        0 => "a",
+        1 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 2 {
+        0 => "a",
+        1 => "b",
+        //~^ match_same_arms
+        2 => "b",
+        #[allow(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 3 {
+        0 => "a",
+        1 => "b",
+        //~^ match_same_arms
+        2 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index 21a8743cc32..f3031619cce 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -1,4 +1,4 @@
-error: this match arm has an identical body to the `_` wildcard arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:17:9
    |
 LL | /         42 => {
@@ -6,14 +6,10 @@ LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
 LL | |             if true {
 ...  |
+LL | |             a
 LL | |         },
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms2.rs:27:9
-   |
+   | |_________^
+LL |
 LL | /         _ => {
 LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
@@ -21,134 +17,169 @@ LL | |             if true {
 ...  |
 LL | |             a
 LL | |         },
-   | |_________^
+   | |_________^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise remove the non-wildcard arm
+   |
+LL -         42 => {
+LL -             foo();
+LL -             let mut a = 42 + [23].len() as i32;
+LL -             if true {
+LL -                 a += 7;
+LL -             }
+LL -             a = -31 - a;
+LL -             a
+LL -         },
+   |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:40:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:39:9
    |
+LL |         42 => foo(),
+   |         ^^^^^^^^^^^
+LL |
 LL |         51 => foo(),
    |         ^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         42 => foo(),
-LL -         51 => foo(),
-LL +         51 | 42 => foo(),
+LL ~
+LL ~         42 | 51 => foo(),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:47:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:46:9
    |
+LL |         Some(_) => 24,
+   |         ^^^^^^^^^^^^^
+LL |
 LL |         None => 24,
    |         ^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         Some(_) => 24,
-LL -         None => 24,
-LL +         None | Some(_) => 24,
+LL ~
+LL ~         Some(_) | None => 24,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:70:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:69:9
    |
+LL |         (Some(a), None) => bar(a),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         (None, Some(a)) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         (Some(a), None) => bar(a),
-LL -         (None, Some(a)) => bar(a),
-LL +         (None, Some(a)) | (Some(a), None) => bar(a),
+LL ~
+LL ~         (Some(a), None) | (None, Some(a)) => bar(a),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:85:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:84:9
    |
+LL |         (Some(a), None) if a == 42 => a,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         (None, Some(a)) if a == 42 => a,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         (Some(a), None) if a == 42 => a,
-LL -         (None, Some(a)) if a == 42 => a,
-LL +         (None, Some(a)) | (Some(a), None) if a == 42 => a,
+LL ~
+LL ~         (Some(a), None) | (None, Some(a)) if a == 42 => a,
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:91:9
    |
 LL |         (Some(a), ..) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         (.., Some(a)) => bar(a),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (Some(a), ..) | (.., Some(a)) => bar(a),
 LL |
 LL ~         _ => (),
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:126:9
    |
 LL |         (Ok(x), Some(_)) => println!("ok {}", x),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         (Ok(_), Some(x)) => println!("ok {}", x),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x),
 LL |
 LL ~         _ => println!("err"),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:143:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:142:9
    |
+LL |         Ok(3) => println!("ok"),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         Ok(_) => println!("ok"),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         Ok(3) => println!("ok"),
-LL -         Ok(_) => println!("ok"),
-LL +         Ok(_) | Ok(3) => println!("ok"),
+LL ~
+LL ~         Ok(3) | Ok(_) => println!("ok"),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:171:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:168:9
    |
+LL | /         0 => {
+LL | |             empty!(0);
+LL | |         },
+   | |_________^
+LL |
 LL | /         1 => {
 LL | |             empty!(0);
 LL | |         },
    | |_________^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         0 => {
-LL -             empty!(0);
-LL -         },
-LL -         1 => {
-LL +         1 | 0 => {
+LL ~
+LL ~         0 | 1 => {
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:222:9
    |
 LL |         Foo::X(0) => 1,
    |         ^^^^^^^^^^^^^^
+...
+LL |         Foo::Z(_) => 1,
+   |         ^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         Foo::X(0) | Foo::Z(_) => 1,
 LL |
@@ -156,60 +187,106 @@ LL |         Foo::X(_) | Foo::Y(_) => 2,
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:233:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:231:9
    |
+LL |         Foo::X(0) => 1,
+   |         ^^^^^^^^^^^^^^
+...
 LL |         Foo::Z(_) => 1,
    |         ^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         Foo::Y(_) | Foo::Z(0) => 2,
-LL ~         Foo::Z(_) | Foo::X(0) => 1,
+LL ~
+LL |         Foo::Y(_) | Foo::Z(0) => 2,
+LL ~         Foo::X(0) | Foo::Z(_) => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:257:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:254:9
    |
+LL |         Some(Bar { x: 0, y: 5, .. }) => 1,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
 LL |         Some(Bar { y: 0, x: 5, .. }) => 1,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         Some(Bar { y: 10, z: 0, .. }) => 2,
+LL ~
+LL |         Some(Bar { y: 10, z: 0, .. }) => 2,
 LL |         None => 50,
-LL ~         Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
+LL ~         Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:272:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:271:9
    |
+LL |         0 => cfg!(not_enable),
+   |         ^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         1 => cfg!(not_enable),
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         0 => cfg!(not_enable),
-LL -         1 => cfg!(not_enable),
-LL +         1 | 0 => cfg!(not_enable),
+LL ~
+LL ~         0 | 1 => cfg!(not_enable),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:289:17
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:288:17
    |
+LL |                 MaybeStaticStr::Static(s) => s,
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |                 MaybeStaticStr::Borrowed(s) => s,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~                 MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s,
    |
-LL -                 MaybeStaticStr::Static(s) => s,
-LL -                 MaybeStaticStr::Borrowed(s) => s,
-LL +                 MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s,
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:306:9
+   |
+LL |         1 => "b",
+   |         ^^^^^^^^
+LL |
+LL |         2 => "b",
+   |         ^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~         1 | 2 => "b",
+LL |
+LL ~         #[allow(clippy::match_same_arms)]
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:315:9
+   |
+LL |         1 => "b",
+   |         ^^^^^^^^
+LL |
+LL |         2 => "b",
+   |         ^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~         1 | 2 => "b",
+LL |
+LL ~         #[expect(clippy::match_same_arms)]
    |
 
-error: aborting due to 14 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
index 0c9398933b8..61a5bd0323a 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
@@ -7,14 +7,22 @@ fn repeat() -> ! {
     panic!()
 }
 
+#[deny(non_exhaustive_omitted_patterns)]
 pub fn f(x: Ordering) {
-    #[deny(non_exhaustive_omitted_patterns)]
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
-        Ordering::AcqRel | Ordering::SeqCst => repeat(),
-        _ => repeat(),
+        //~^ match_same_arms
+        Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+    }
+
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        //~^ match_same_arms
+        Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
     }
 }
 
@@ -28,21 +36,21 @@ mod f {
             Ordering::Relaxed => println!("relaxed"),
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
-            Ordering::AcqRel | Ordering::SeqCst => repeat(),
-            _ => repeat(),
+            //~^ match_same_arms
+            Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
         }
     }
 }
 
-// Below should still lint
+// Below can still suggest removing the other patterns
 
 pub fn g(x: Ordering) {
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
-        //~^ match_same_arms
         _ => repeat(),
+        //~^ match_same_arms
     }
 }
 
@@ -54,8 +62,8 @@ mod g {
             Ordering::Relaxed => println!("relaxed"),
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
-            //~^ match_same_arms
             _ => repeat(),
+            //~^ match_same_arms
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
index 304a9e5c28e..66f65eb39d0 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
@@ -7,15 +7,25 @@ fn repeat() -> ! {
     panic!()
 }
 
+#[deny(non_exhaustive_omitted_patterns)]
 pub fn f(x: Ordering) {
-    #[deny(non_exhaustive_omitted_patterns)]
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+        //~^ match_same_arms
         _ => repeat(),
     }
+
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        Ordering::AcqRel => repeat(),
+        //~^ match_same_arms
+        Ordering::SeqCst | _ => repeat(),
+    }
 }
 
 mod f {
@@ -29,12 +39,13 @@ mod f {
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+            //~^ match_same_arms
             _ => repeat(),
         }
     }
 }
 
-// Below should still lint
+// Below can still suggest removing the other patterns
 
 pub fn g(x: Ordering) {
     match x {
@@ -42,8 +53,8 @@ pub fn g(x: Ordering) {
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-        //~^ match_same_arms
         _ => repeat(),
+        //~^ match_same_arms
     }
 }
 
@@ -56,8 +67,8 @@ mod g {
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-            //~^ match_same_arms
             _ => repeat(),
+            //~^ match_same_arms
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
index aa7f8c95dce..03252f346c6 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
@@ -1,32 +1,80 @@
-error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:44:9
-   |
-LL | /         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:46:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:16:9
    |
+LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         _ => repeat(),
    |         ^^^^^^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~         Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+   |
 
-error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:58:13
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:25:9
+   |
+LL |         Ordering::AcqRel => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         Ordering::SeqCst | _ => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | /             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-LL | |
-   | |____________^ help: try removing the arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:60:13
+LL ~
+LL ~         Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
    |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:41:13
+   |
+LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |             _ => repeat(),
    |             ^^^^^^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~             Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:55:9
+   |
+LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         _ => repeat(),
+   |         ^^^^^^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arm
+   |
+LL -         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:69:13
+   |
+LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             _ => repeat(),
+   |             ^^^^^^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arm
+   |
+LL -             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed b/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed
new file mode 100644
index 00000000000..882ff6bf894
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a += 1;
+    //~^ misrefactored_assign_op
+
+    a += 1;
+    //~^ misrefactored_assign_op
+
+    a -= 1;
+    //~^ misrefactored_assign_op
+
+    a *= 99;
+    //~^ misrefactored_assign_op
+
+    a *= 42;
+    //~^ misrefactored_assign_op
+
+    a /= 2;
+    //~^ misrefactored_assign_op
+
+    a %= 5;
+    //~^ misrefactored_assign_op
+
+    a &= 1;
+    //~^ misrefactored_assign_op
+
+    a *= a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed b/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed
new file mode 100644
index 00000000000..de3a0f1710d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a = a + a + 1;
+    //~^ misrefactored_assign_op
+
+    a = a + 1 + a;
+    //~^ misrefactored_assign_op
+
+    a = a - (a - 1);
+    //~^ misrefactored_assign_op
+
+    a = a * a * 99;
+    //~^ misrefactored_assign_op
+
+    a = a * 42 * a;
+    //~^ misrefactored_assign_op
+
+    a = a / (a / 2);
+    //~^ misrefactored_assign_op
+
+    a = a % (a % 5);
+    //~^ misrefactored_assign_op
+
+    a = a & a & 1;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.rs b/src/tools/clippy/tests/ui/misrefactored_assign_op.rs
new file mode 100644
index 00000000000..62d83d1619c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.rs
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a += a + 1;
+    //~^ misrefactored_assign_op
+
+    a += 1 + a;
+    //~^ misrefactored_assign_op
+
+    a -= a - 1;
+    //~^ misrefactored_assign_op
+
+    a *= a * 99;
+    //~^ misrefactored_assign_op
+
+    a *= 42 * a;
+    //~^ misrefactored_assign_op
+
+    a /= a / 2;
+    //~^ misrefactored_assign_op
+
+    a %= a % 5;
+    //~^ misrefactored_assign_op
+
+    a &= a & 1;
+    //~^ misrefactored_assign_op
+
+    a *= a * a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/misrefactored_assign_op.stderr
index d9ecd3f8b23..63f3a3e28f1 100644
--- a/src/tools/clippy/tests/ui/assign_ops2.stderr
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.stderr
@@ -1,5 +1,5 @@
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:8:5
+  --> tests/ui/misrefactored_assign_op.rs:6:5
    |
 LL |     a += a + 1;
    |     ^^^^^^^^^^
@@ -18,7 +18,7 @@ LL +     a = a + a + 1;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:11:5
+  --> tests/ui/misrefactored_assign_op.rs:9:5
    |
 LL |     a += 1 + a;
    |     ^^^^^^^^^^
@@ -35,7 +35,7 @@ LL +     a = a + 1 + a;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:14:5
+  --> tests/ui/misrefactored_assign_op.rs:12:5
    |
 LL |     a -= a - 1;
    |     ^^^^^^^^^^
@@ -52,7 +52,7 @@ LL +     a = a - (a - 1);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:17:5
+  --> tests/ui/misrefactored_assign_op.rs:15:5
    |
 LL |     a *= a * 99;
    |     ^^^^^^^^^^^
@@ -69,7 +69,7 @@ LL +     a = a * a * 99;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:20:5
+  --> tests/ui/misrefactored_assign_op.rs:18:5
    |
 LL |     a *= 42 * a;
    |     ^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL +     a = a * 42 * a;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:23:5
+  --> tests/ui/misrefactored_assign_op.rs:21:5
    |
 LL |     a /= a / 2;
    |     ^^^^^^^^^^
@@ -103,7 +103,7 @@ LL +     a = a / (a / 2);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:26:5
+  --> tests/ui/misrefactored_assign_op.rs:24:5
    |
 LL |     a %= a % 5;
    |     ^^^^^^^^^^
@@ -120,7 +120,7 @@ LL +     a = a % (a % 5);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:29:5
+  --> tests/ui/misrefactored_assign_op.rs:27:5
    |
 LL |     a &= a & 1;
    |     ^^^^^^^^^^
@@ -137,7 +137,7 @@ LL +     a = a & a & 1;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:32:5
+  --> tests/ui/misrefactored_assign_op.rs:30:5
    |
 LL |     a *= a * a;
    |     ^^^^^^^^^^
@@ -153,14 +153,5 @@ LL -     a *= a * a;
 LL +     a = a * a * a;
    |
 
-error: manual implementation of an assign operation
-  --> tests/ui/assign_ops2.rs:71:5
-   |
-LL |     buf = buf + cows.clone();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
-   |
-   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_match.fixed b/src/tools/clippy/tests/ui/needless_match.fixed
index b2c2bbfaa36..41acf44023f 100644
--- a/src/tools/clippy/tests/ui/needless_match.fixed
+++ b/src/tools/clippy/tests/ui/needless_match.fixed
@@ -301,4 +301,16 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result<i32, &'static str>) -> Result<i32, &'static str> {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = t;
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.rs b/src/tools/clippy/tests/ui/needless_match.rs
index 1cb670edc60..936653b961b 100644
--- a/src/tools/clippy/tests/ui/needless_match.rs
+++ b/src/tools/clippy/tests/ui/needless_match.rs
@@ -364,4 +364,19 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result<i32, &'static str>) -> Result<i32, &'static str> {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => err,
+    };
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.stderr b/src/tools/clippy/tests/ui/needless_match.stderr
index 719b0ef8846..5195ecdfa55 100644
--- a/src/tools/clippy/tests/ui/needless_match.stderr
+++ b/src/tools/clippy/tests/ui/needless_match.stderr
@@ -151,5 +151,15 @@ LL | |             None
 LL | |         }
    | |_________^ help: replace it with: `A`
 
-error: aborting due to 14 previous errors
+error: this match expression is unnecessary
+  --> tests/ui/needless_match.rs:373:13
+   |
+LL |       let x = match t {
+   |  _____________^
+LL | |         Ok(v) => Ok::<_, &'static str>(v),
+LL | |         err @ Err(_) => err,
+LL | |     };
+   | |_____^ help: replace it with: `t`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index ad625ad6d50..17d3862cd86 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -84,14 +84,14 @@ fn test_macro_call() -> i32 {
 }
 
 fn test_void_fun() {
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 fn test_void_if_fun(b: bool) {
     if b {
-        //~^^ needless_return
+        //~^ needless_return
     } else {
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -108,7 +108,7 @@ fn test_nested_match(x: u32) {
         0 => (),
         1 => {
             let _ = 42;
-            //~^^ needless_return
+            //~^ needless_return
         },
         _ => (),
         //~^ needless_return
@@ -156,7 +156,7 @@ mod issue6501 {
 
     fn test_closure() {
         let _ = || {
-            //~^^ needless_return
+            //~^ needless_return
         };
         let _ = || {};
         //~^ needless_return
@@ -220,14 +220,14 @@ async fn async_test_macro_call() -> i32 {
 }
 
 async fn async_test_void_fun() {
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 async fn async_test_void_if_fun(b: bool) {
     if b {
-        //~^^ needless_return
+        //~^ needless_return
     } else {
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -354,7 +354,7 @@ fn issue9503(x: usize) -> isize {
 mod issue9416 {
     pub fn with_newline() {
         let _ = 42;
-        //~^^ needless_return
+        //~^ needless_return
     }
 
     #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 41d7e5bdd50..1c6e7ffa1ee 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -85,16 +85,16 @@ fn test_macro_call() -> i32 {
 
 fn test_void_fun() {
     return;
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 fn test_void_if_fun(b: bool) {
     if b {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     } else {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -112,7 +112,7 @@ fn test_nested_match(x: u32) {
         1 => {
             let _ = 42;
             return;
-            //~^^ needless_return
+            //~^ needless_return
         },
         _ => return,
         //~^ needless_return
@@ -161,7 +161,7 @@ mod issue6501 {
     fn test_closure() {
         let _ = || {
             return;
-            //~^^ needless_return
+            //~^ needless_return
         };
         let _ = || return;
         //~^ needless_return
@@ -226,16 +226,16 @@ async fn async_test_macro_call() -> i32 {
 
 async fn async_test_void_fun() {
     return;
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 async fn async_test_void_if_fun(b: bool) {
     if b {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     } else {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -363,7 +363,7 @@ mod issue9416 {
     pub fn with_newline() {
         let _ = 42;
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 
     #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 80863b9b62b..26dd265379b 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -133,12 +133,10 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:86:21
+  --> tests/ui/needless_return.rs:87:5
    |
-LL |   fn test_void_fun() {
-   |  _____________________^
-LL | |     return;
-   | |__________^
+LL |     return;
+   |     ^^^^^^
    |
 help: remove `return`
    |
@@ -148,12 +146,10 @@ LL + fn test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:92:11
+  --> tests/ui/needless_return.rs:93:9
    |
-LL |       if b {
-   |  ___________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -163,12 +159,10 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:95:13
+  --> tests/ui/needless_return.rs:96:9
    |
-LL |       } else {
-   |  _____________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -190,12 +184,10 @@ LL +         _ => (),
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:113:24
+  --> tests/ui/needless_return.rs:114:13
    |
-LL |               let _ = 42;
-   |  ________________________^
-LL | |             return;
-   | |__________________^
+LL |             return;
+   |             ^^^^^^
    |
 help: remove `return`
    |
@@ -253,12 +245,10 @@ LL +         bar.unwrap_or_else(|_| {})
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:162:21
+  --> tests/ui/needless_return.rs:163:13
    |
-LL |           let _ = || {
-   |  _____________________^
-LL | |             return;
-   | |__________________^
+LL |             return;
+   |             ^^^^^^
    |
 help: remove `return`
    |
@@ -400,12 +390,10 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:227:33
+  --> tests/ui/needless_return.rs:228:5
    |
-LL |   async fn async_test_void_fun() {
-   |  _________________________________^
-LL | |     return;
-   | |__________^
+LL |     return;
+   |     ^^^^^^
    |
 help: remove `return`
    |
@@ -415,12 +403,10 @@ LL + async fn async_test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:233:11
+  --> tests/ui/needless_return.rs:234:9
    |
-LL |       if b {
-   |  ___________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -430,12 +416,10 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:236:13
+  --> tests/ui/needless_return.rs:237:9
    |
-LL |       } else {
-   |  _____________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -593,12 +577,10 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:364:20
+  --> tests/ui/needless_return.rs:365:9
    |
-LL |           let _ = 42;
-   |  ____________________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -608,10 +590,10 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:371:20
+  --> tests/ui/needless_return.rs:371:21
    |
 LL |         let _ = 42; return;
-   |                    ^^^^^^^
+   |                     ^^^^^^
    |
 help: remove `return`
    |
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index 703c2a3d984..4ab5bc9acde 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -221,3 +221,56 @@ fn main() {
     Cout << 142;
     -Cout;
 }
+
+fn issue14592() {
+    struct MyStruct {
+        _inner: MyInner,
+    }
+    struct MyInner {}
+
+    impl Drop for MyInner {
+        fn drop(&mut self) {
+            println!("dropping");
+        }
+    }
+
+    let x = MyStruct { _inner: MyInner {} };
+
+    let closure = || {
+        // Do not lint: dropping the assignment or assigning to `_` would
+        // change the output.
+        let _x = x;
+    };
+
+    println!("1");
+    closure();
+    println!("2");
+
+    struct Innocuous {
+        a: i32,
+    }
+
+    // Do not lint: one of the fields has a side effect.
+    let x = MyInner {};
+    let closure = || {
+        let _x = Innocuous {
+            a: {
+                x;
+                10
+            },
+        };
+    };
+
+    // Do not lint: the base has a side effect.
+    let x = MyInner {};
+    let closure = || {
+        let _x = Innocuous {
+            ..Innocuous {
+                a: {
+                    x;
+                    10
+                },
+            }
+        };
+    };
+}
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 55e287b9159..ff81c642602 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -7,85 +7,107 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
 #![allow(clippy::box_collection)]
+#![allow(invalid_reference_casting)]
+#![allow(suspicious_double_ref_op)]
+#![allow(invalid_nan_comparisons)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(double_negations)]
+#![allow(drop_bounds)]
+#![allow(dropping_copy_types)]
+#![allow(dropping_references)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
+#![allow(clippy::manual_find_map)]
 #![allow(unpredictable_function_pointer_comparisons)]
+#![allow(useless_ptr_null_checks)]
+#![allow(for_loops_over_fallibles)]
+#![allow(forgetting_copy_types)]
+#![allow(forgetting_references)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
+#![allow(array_into_iter)]
+#![allow(invalid_atomic_ordering)]
+#![allow(invalid_null_arguments)]
+#![allow(invalid_value)]
+#![allow(invalid_from_utf8_unchecked)]
+#![allow(let_underscore_drop)]
 #![allow(clippy::overly_complex_bool_expr)]
+#![allow(unexpected_cfgs)]
+#![allow(enum_intrinsics_non_enums)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
+#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
-#![allow(clippy::unwrap_or_default)]
-#![allow(clippy::invisible_characters)]
-#![allow(invalid_reference_casting)]
-#![allow(suspicious_double_ref_op)]
-#![allow(invalid_nan_comparisons)]
-#![allow(invalid_null_arguments)]
-#![allow(double_negations)]
-#![allow(drop_bounds)]
-#![allow(dropping_copy_types)]
-#![allow(dropping_references)]
-#![allow(useless_ptr_null_checks)]
-#![allow(for_loops_over_fallibles)]
-#![allow(forgetting_copy_types)]
-#![allow(forgetting_references)]
-#![allow(array_into_iter)]
-#![allow(invalid_atomic_ordering)]
-#![allow(invalid_value)]
-#![allow(invalid_from_utf8_unchecked)]
-#![allow(let_underscore_drop)]
-#![allow(unexpected_cfgs)]
-#![allow(enum_intrinsics_non_enums)]
-#![allow(non_fmt_panics)]
-#![allow(named_arguments_used_positionally)]
-#![allow(dangling_pointers_from_temporaries)]
+#![allow(unnecessary_transmutes)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
-#![allow(unnecessary_transmutes)]
+#![allow(clippy::invisible_characters)]
 #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
 #![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec`
+#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
 #![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime`
 #![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
 #![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
 #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
+#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
 #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
 #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
 #![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
 #![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
 #![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
+#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
 #![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive`
 #![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some`
 #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used`
@@ -93,49 +115,27 @@
 #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
 #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
 #![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
+#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
 #![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref`
 #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
+#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
 #![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display`
-#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
-#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
-#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
-#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
-#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
-#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
-#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
-#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
-#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
-#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
-#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
-#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
-#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
-#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
-#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
-#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
-#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
-#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
-#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
-#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
-#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
 #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
+#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 31dcd2cea08..b5d5d07e639 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -7,85 +7,107 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
 #![allow(clippy::box_collection)]
+#![allow(invalid_reference_casting)]
+#![allow(suspicious_double_ref_op)]
+#![allow(invalid_nan_comparisons)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(double_negations)]
+#![allow(drop_bounds)]
+#![allow(dropping_copy_types)]
+#![allow(dropping_references)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
+#![allow(clippy::manual_find_map)]
 #![allow(unpredictable_function_pointer_comparisons)]
+#![allow(useless_ptr_null_checks)]
+#![allow(for_loops_over_fallibles)]
+#![allow(forgetting_copy_types)]
+#![allow(forgetting_references)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
+#![allow(array_into_iter)]
+#![allow(invalid_atomic_ordering)]
+#![allow(invalid_null_arguments)]
+#![allow(invalid_value)]
+#![allow(invalid_from_utf8_unchecked)]
+#![allow(let_underscore_drop)]
 #![allow(clippy::overly_complex_bool_expr)]
+#![allow(unexpected_cfgs)]
+#![allow(enum_intrinsics_non_enums)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
+#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
-#![allow(clippy::unwrap_or_default)]
-#![allow(clippy::invisible_characters)]
-#![allow(invalid_reference_casting)]
-#![allow(suspicious_double_ref_op)]
-#![allow(invalid_nan_comparisons)]
-#![allow(invalid_null_arguments)]
-#![allow(double_negations)]
-#![allow(drop_bounds)]
-#![allow(dropping_copy_types)]
-#![allow(dropping_references)]
-#![allow(useless_ptr_null_checks)]
-#![allow(for_loops_over_fallibles)]
-#![allow(forgetting_copy_types)]
-#![allow(forgetting_references)]
-#![allow(array_into_iter)]
-#![allow(invalid_atomic_ordering)]
-#![allow(invalid_value)]
-#![allow(invalid_from_utf8_unchecked)]
-#![allow(let_underscore_drop)]
-#![allow(unexpected_cfgs)]
-#![allow(enum_intrinsics_non_enums)]
-#![allow(non_fmt_panics)]
-#![allow(named_arguments_used_positionally)]
-#![allow(dangling_pointers_from_temporaries)]
+#![allow(unnecessary_transmutes)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
-#![allow(unnecessary_transmutes)]
+#![allow(clippy::invisible_characters)]
 #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
 #![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
 #![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
 #![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
 #![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime`
 #![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
 #![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
 #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
+#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
 #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
 #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
 #![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
 #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
 #![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
+#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
 #![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive`
 #![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some`
 #![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used`
@@ -93,49 +115,27 @@
 #![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
 #![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
 #![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
+#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
 #![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref`
 #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
 #![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display`
-#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
-#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
-#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
-#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
-#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
-#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
-#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
-#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
-#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
-#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
-#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
-#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
-#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
-#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
-#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
-#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
-#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
-#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
-#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
-#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
-#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
-#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
-#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
-#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 #![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
 #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
-#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float`
-#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char`
-#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int`
-#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
+#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index a8d5c96acc3..2487dfc8eba 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -37,407 +37,407 @@ error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
   --> tests/ui/rename.rs:73:9
    |
+LL | #![warn(clippy::cast_ref_to_mut)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
+
+error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
+  --> tests/ui/rename.rs:74:9
+   |
+LL | #![warn(clippy::clone_double_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
+
+error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
+  --> tests/ui/rename.rs:75:9
+   |
+LL | #![warn(clippy::cmp_nan)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+  --> tests/ui/rename.rs:76:9
+   |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:78:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
-error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:78:9
-   |
-LL | #![warn(clippy::eval_order_dependence)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
-
-error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
-  --> tests/ui/rename.rs:79:9
-   |
-LL | #![warn(clippy::find_map)]
-   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
-
-error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
-  --> tests/ui/rename.rs:80:9
-   |
-LL | #![warn(clippy::filter_map)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
-
-error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
+error: lint `clippy::double_neg` has been renamed to `double_negations`
   --> tests/ui/rename.rs:81:9
    |
-LL | #![warn(clippy::fn_address_comparisons)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+LL | #![warn(clippy::double_neg)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
 
-error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
   --> tests/ui/rename.rs:82:9
    |
-LL | #![warn(clippy::identity_conversion)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+LL | #![warn(clippy::drop_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
-error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
+error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
   --> tests/ui/rename.rs:83:9
    |
-LL | #![warn(clippy::if_let_redundant_pattern_matching)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
+LL | #![warn(clippy::drop_copy)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
-error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+error: lint `clippy::drop_ref` has been renamed to `dropping_references`
   --> tests/ui/rename.rs:84:9
    |
-LL | #![warn(clippy::if_let_some_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+LL | #![warn(clippy::drop_ref)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
-error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
+error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
   --> tests/ui/rename.rs:85:9
    |
-LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
+LL | #![warn(clippy::eval_order_dependence)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
-error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
+error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
   --> tests/ui/rename.rs:86:9
    |
-LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
+LL | #![warn(clippy::filter_map)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
 
-error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
+error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
   --> tests/ui/rename.rs:87:9
    |
-LL | #![warn(clippy::integer_arithmetic)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
 
-error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
   --> tests/ui/rename.rs:88:9
    |
-LL | #![warn(clippy::logic_bug)]
-   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+LL | #![warn(clippy::fn_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
 
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
   --> tests/ui/rename.rs:89:9
    |
-LL | #![warn(clippy::new_without_default_derive)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::fn_null_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
-error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
+error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:90:9
    |
-LL | #![warn(clippy::option_and_then_some)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
+LL | #![warn(clippy::for_loop_over_option)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
+error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:91:9
    |
-LL | #![warn(clippy::option_expect_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+LL | #![warn(clippy::for_loop_over_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:92:9
    |
-LL | #![warn(clippy::option_map_unwrap_or)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::for_loops_over_fallibles)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
   --> tests/ui/rename.rs:93:9
    |
-LL | #![warn(clippy::option_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::forget_copy)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
-error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
   --> tests/ui/rename.rs:94:9
    |
-LL | #![warn(clippy::option_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::forget_ref)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
-error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
   --> tests/ui/rename.rs:95:9
    |
-LL | #![warn(clippy::overflow_check_conditional)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
+LL | #![warn(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
-error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
+error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
   --> tests/ui/rename.rs:96:9
    |
-LL | #![warn(clippy::ref_in_deref)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
-error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
   --> tests/ui/rename.rs:97:9
    |
-LL | #![warn(clippy::result_expect_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+LL | #![warn(clippy::if_let_some_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
-error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
   --> tests/ui/rename.rs:98:9
    |
-LL | #![warn(clippy::result_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
-error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
   --> tests/ui/rename.rs:99:9
    |
-LL | #![warn(clippy::result_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
-error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
   --> tests/ui/rename.rs:100:9
    |
-LL | #![warn(clippy::single_char_push_str)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+LL | #![warn(clippy::integer_arithmetic)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
   --> tests/ui/rename.rs:101:9
    |
-LL | #![warn(clippy::stutter)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::into_iter_on_array)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
-error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
   --> tests/ui/rename.rs:102:9
    |
-LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
+LL | #![warn(clippy::invalid_atomic_ordering)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
-error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
+error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
   --> tests/ui/rename.rs:103:9
    |
-LL | #![warn(clippy::to_string_in_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
+LL | #![warn(clippy::invalid_null_ptr_usage)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
 
-error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
   --> tests/ui/rename.rs:104:9
    |
-LL | #![warn(clippy::unwrap_or_else_default)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+LL | #![warn(clippy::invalid_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
-error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
   --> tests/ui/rename.rs:105:9
    |
-LL | #![warn(clippy::zero_width_space)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+LL | #![warn(clippy::invalid_utf8_in_unchecked)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
-error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
+error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
   --> tests/ui/rename.rs:106:9
    |
-LL | #![warn(clippy::cast_ref_to_mut)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
+LL | #![warn(clippy::let_underscore_drop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
-error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
   --> tests/ui/rename.rs:107:9
    |
-LL | #![warn(clippy::clone_double_ref)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
+LL | #![warn(clippy::logic_bug)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
-error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
+error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
   --> tests/ui/rename.rs:108:9
    |
-LL | #![warn(clippy::cmp_nan)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
+LL | #![warn(clippy::maybe_misused_cfg)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
-error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
   --> tests/ui/rename.rs:109:9
    |
-LL | #![warn(clippy::invalid_null_ptr_usage)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
-error: lint `clippy::double_neg` has been renamed to `double_negations`
+error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
   --> tests/ui/rename.rs:110:9
    |
-LL | #![warn(clippy::double_neg)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
+LL | #![warn(clippy::mismatched_target_os)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
   --> tests/ui/rename.rs:111:9
    |
-LL | #![warn(clippy::drop_bounds)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::new_without_default_derive)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
-error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
   --> tests/ui/rename.rs:112:9
    |
-LL | #![warn(clippy::drop_copy)]
-   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
+LL | #![warn(clippy::option_and_then_some)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
-error: lint `clippy::drop_ref` has been renamed to `dropping_references`
+error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
   --> tests/ui/rename.rs:113:9
    |
-LL | #![warn(clippy::drop_ref)]
-   |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
+LL | #![warn(clippy::option_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:114:9
    |
-LL | #![warn(clippy::fn_null_check)]
-   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
+LL | #![warn(clippy::option_map_unwrap_or)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:115:9
    |
-LL | #![warn(clippy::for_loop_over_option)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> tests/ui/rename.rs:116:9
    |
-LL | #![warn(clippy::for_loop_over_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::option_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
   --> tests/ui/rename.rs:117:9
    |
-LL | #![warn(clippy::for_loops_over_fallibles)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::overflow_check_conditional)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
-error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
   --> tests/ui/rename.rs:118:9
    |
-LL | #![warn(clippy::forget_copy)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
+LL | #![warn(clippy::panic_params)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
-error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
+error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
   --> tests/ui/rename.rs:119:9
    |
-LL | #![warn(clippy::forget_ref)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
+LL | #![warn(clippy::positional_named_format_parameters)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
   --> tests/ui/rename.rs:120:9
    |
-LL | #![warn(clippy::into_iter_on_array)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+LL | #![warn(clippy::ref_in_deref)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
   --> tests/ui/rename.rs:121:9
    |
-LL | #![warn(clippy::invalid_atomic_ordering)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+LL | #![warn(clippy::result_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:122:9
    |
-LL | #![warn(clippy::invalid_ref)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> tests/ui/rename.rs:123:9
    |
-LL | #![warn(clippy::invalid_utf8_in_unchecked)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
+LL | #![warn(clippy::result_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
   --> tests/ui/rename.rs:124:9
    |
-LL | #![warn(clippy::let_underscore_drop)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
+LL | #![warn(clippy::reverse_range_loop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
   --> tests/ui/rename.rs:125:9
    |
-LL | #![warn(clippy::maybe_misused_cfg)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+LL | #![warn(clippy::single_char_push_str)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
   --> tests/ui/rename.rs:126:9
    |
-LL | #![warn(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::stutter)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
-error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
   --> tests/ui/rename.rs:127:9
    |
-LL | #![warn(clippy::mismatched_target_os)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
   --> tests/ui/rename.rs:128:9
    |
-LL | #![warn(clippy::panic_params)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
-error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
+error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
   --> tests/ui/rename.rs:129:9
    |
-LL | #![warn(clippy::positional_named_format_parameters)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
+LL | #![warn(clippy::to_string_in_display)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:130:9
    |
-LL | #![warn(clippy::temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+LL | #![warn(clippy::transmute_float_to_int)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
+error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:131:9
    |
-LL | #![warn(clippy::undropped_manually_drops)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
+LL | #![warn(clippy::transmute_int_to_char)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
+error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:132:9
    |
-LL | #![warn(clippy::unknown_clippy_lints)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+LL | #![warn(clippy::transmute_int_to_float)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
+error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:133:9
    |
-LL | #![warn(clippy::unused_label)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::transmute_num_to_bytes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
+error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
   --> tests/ui/rename.rs:134:9
    |
-LL | #![warn(clippy::vtable_address_comparisons)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
+LL | #![warn(clippy::undropped_manually_drops)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
-error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
   --> tests/ui/rename.rs:135:9
    |
-LL | #![warn(clippy::reverse_range_loop)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+LL | #![warn(clippy::unknown_clippy_lints)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
-error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
   --> tests/ui/rename.rs:136:9
    |
-LL | #![warn(clippy::transmute_int_to_float)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::unused_label)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
   --> tests/ui/rename.rs:137:9
    |
-LL | #![warn(clippy::transmute_int_to_char)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::unwrap_or_else_default)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
-error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
   --> tests/ui/rename.rs:138:9
    |
-LL | #![warn(clippy::transmute_float_to_int)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::vtable_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
   --> tests/ui/rename.rs:139:9
    |
-LL | #![warn(clippy::transmute_num_to_bytes)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::zero_width_space)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: aborting due to 73 previous errors
 
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
index a98b73c9e1c..3f205b322ab 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
@@ -31,34 +31,34 @@ fn ifs_same_cond_fn() {
     let obj = Struct;
 
     if function() {
-    } else if function() {
         //~^ same_functions_in_if_condition
+    } else if function() {
     }
 
     if fn_arg(a) {
-    } else if fn_arg(a) {
         //~^ same_functions_in_if_condition
+    } else if fn_arg(a) {
     }
 
     if obj.method() {
-    } else if obj.method() {
         //~^ same_functions_in_if_condition
+    } else if obj.method() {
     }
 
     if obj.method_arg(a) {
-    } else if obj.method_arg(a) {
         //~^ same_functions_in_if_condition
+    } else if obj.method_arg(a) {
     }
 
     let mut v = vec![1];
     if v.pop().is_none() {
-    } else if v.pop().is_none() {
         //~^ same_functions_in_if_condition
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
-    } else if v.len() == 42 {
         //~^ same_functions_in_if_condition
+    } else if v.len() == 42 {
     }
 
     if v.len() == 1 {
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
index 35dcbadce59..59f4511757d 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
@@ -1,79 +1,62 @@
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:34:15
-   |
-LL |     } else if function() {
-   |               ^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:33:8
    |
 LL |     if function() {
    |        ^^^^^^^^^^
+LL |
+LL |     } else if function() {
+   |               ^^^^^^^^^^
+   |
 note: the lint level is defined here
   --> tests/ui/same_functions_in_if_condition.rs:2:9
    |
 LL | #![deny(clippy::same_functions_in_if_condition)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:39:15
-   |
-LL |     } else if fn_arg(a) {
-   |               ^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:38:8
    |
 LL |     if fn_arg(a) {
    |        ^^^^^^^^^
+LL |
+LL |     } else if fn_arg(a) {
+   |               ^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:44:15
-   |
-LL |     } else if obj.method() {
-   |               ^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:43:8
    |
 LL |     if obj.method() {
    |        ^^^^^^^^^^^^
+LL |
+LL |     } else if obj.method() {
+   |               ^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:49:15
-   |
-LL |     } else if obj.method_arg(a) {
-   |               ^^^^^^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:48:8
    |
 LL |     if obj.method_arg(a) {
    |        ^^^^^^^^^^^^^^^^^
-
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:55:15
-   |
-LL |     } else if v.pop().is_none() {
+LL |
+LL |     } else if obj.method_arg(a) {
    |               ^^^^^^^^^^^^^^^^^
-   |
-note: same as this
+
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:54:8
    |
 LL |     if v.pop().is_none() {
    |        ^^^^^^^^^^^^^^^^^
+LL |
+LL |     } else if v.pop().is_none() {
+   |               ^^^^^^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:60:15
-   |
-LL |     } else if v.len() == 42 {
-   |               ^^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:59:8
    |
 LL |     if v.len() == 42 {
    |        ^^^^^^^^^^^^^
+LL |
+LL |     } else if v.len() == 42 {
+   |               ^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
index c6c0cb347dc..25884450b08 100644
--- a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
+++ b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macros.rs
 //@no-rustfix: overlapping suggestions
-#![allow(clippy::no_effect, clippy::useless_vec, unused)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
 #![warn(clippy::single_range_in_vec_init)]
 #![feature(generic_arg_infer)]
 
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed
index c96a53ba2cd..c96a53ba2cd 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
+++ b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.fixed
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs
index a3a35eb26d1..a3a35eb26d1 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
+++ b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr
index e334ca5241e..4998b9bd2cc 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
+++ b/src/tools/clippy/tests/ui/skip_rustfmt/non_expressive_names_error_recovery.stderr
@@ -1,5 +1,5 @@
 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
-  --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19
+  --> tests/ui/skip_rustfmt/non_expressive_names_error_recovery.rs:6:19
    |
 LL | fn aa(a: Aa<String) {
    |                   ^ expected one of 7 possible tokens
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index b064a8b8f46..316eac0b58b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -675,3 +675,9 @@ mod issue_14242 {
         rc_slice_provider().to_vec().into_iter()
     }
 }
+
+fn issue14833() {
+    use std::collections::HashSet;
+    let mut s = HashSet::<&String>::new();
+    s.remove(&"hello".to_owned());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 7954a4ad4ce..f2dbd1db3c9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -675,3 +675,9 @@ mod issue_14242 {
         rc_slice_provider().to_vec().into_iter()
     }
 }
+
+fn issue14833() {
+    use std::collections::HashSet;
+    let mut s = HashSet::<&String>::new();
+    s.remove(&"hello".to_owned());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
index ba562f5a50b..13d71271e21 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
@@ -1,13 +1,8 @@
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:9:1
    |
-LL | / fn func1(a: bool, b: bool) -> Option<i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn func1(a: bool, b: bool) -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unnecessary-wraps` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_wraps)]`
@@ -16,7 +11,7 @@ help: remove `Option` from the return type...
 LL - fn func1(a: bool, b: bool) -> Option<i32> {
 LL + fn func1(a: bool, b: bool) -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL ~         return 42;
 LL |     }
@@ -30,21 +25,15 @@ LL ~         return 1337;
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:24:1
    |
-LL | / fn func2(a: bool, b: bool) -> Option<i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | |     if a { Some(20) } else { Some(30) }
-LL | | }
-   | |_^
+LL | fn func2(a: bool, b: bool) -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL - fn func2(a: bool, b: bool) -> Option<i32> {
 LL + fn func2(a: bool, b: bool) -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL ~         return 10;
 LL |     }
@@ -54,19 +43,15 @@ LL ~     if a { 20 } else { 30 }
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:44:1
    |
-LL | / fn func5() -> Option<i32> {
-LL | |
-LL | |
-LL | |     Some(1)
-LL | | }
-   | |_^
+LL | fn func5() -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL - fn func5() -> Option<i32> {
 LL + fn func5() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL -     Some(1)
 LL +     1
@@ -75,19 +60,15 @@ LL +     1
 error: this function's return value is unnecessarily wrapped by `Result`
   --> tests/ui/unnecessary_wraps.rs:56:1
    |
-LL | / fn func7() -> Result<i32, ()> {
-LL | |
-LL | |
-LL | |     Ok(1)
-LL | | }
-   | |_^
+LL | fn func7() -> Result<i32, ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Result` from the return type...
    |
 LL - fn func7() -> Result<i32, ()> {
 LL + fn func7() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Ok()` from returning expressions
    |
 LL -     Ok(1)
 LL +     1
@@ -96,19 +77,15 @@ LL +     1
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:86:5
    |
-LL | /     fn func12() -> Option<i32> {
-LL | |
-LL | |
-LL | |         Some(1)
-LL | |     }
-   | |_____^
+LL |     fn func12() -> Option<i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL -     fn func12() -> Option<i32> {
 LL +     fn func12() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL -         Some(1)
 LL +         1
@@ -117,13 +94,8 @@ LL +         1
 error: this function's return value is unnecessary
   --> tests/ui/unnecessary_wraps.rs:115:1
    |
-LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the return type...
    |
@@ -144,13 +116,8 @@ LL ~         return ;
 error: this function's return value is unnecessary
   --> tests/ui/unnecessary_wraps.rs:130:1
    |
-LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the return type...
    |
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index 8c1f948fb58..3c3ea5a736d 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -248,6 +248,16 @@ impl Issue12357 {
     }
 }
 
+fn issue_14828() {
+    pub trait T {
+        fn as_ref(&self) {}
+    }
+
+    impl T for () {}
+
+    ().as_ref();
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index d9db2d4f559..c173dd67715 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -248,6 +248,16 @@ impl Issue12357 {
     }
 }
 
+fn issue_14828() {
+    pub trait T {
+        fn as_ref(&self) {}
+    }
+
+    impl T for () {}
+
+    ().as_ref();
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_concat.fixed b/src/tools/clippy/tests/ui/useless_concat.fixed
new file mode 100644
index 00000000000..360b6f6ce82
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.fixed
@@ -0,0 +1,41 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::useless_concat)]
+#![allow(clippy::print_literal)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+macro_rules! my_concat {
+    ($fmt:literal $(, $e:expr)*) => {
+        println!(concat!("ERROR: ", $fmt), $($e,)*);
+    }
+}
+
+fn main() {
+    let x = ""; //~ useless_concat
+    let x = "c"; //~ useless_concat
+    let x = "\""; //~ useless_concat
+    let x = "true"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "a😀\n"; //~ useless_concat
+    let x = "a"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    println!("b: {}", "a"); //~ useless_concat
+    // Should not lint.
+    let x = concat!("a", "b");
+    let local_i32 = 1;
+    my_concat!("{}", local_i32);
+    let x = concat!(file!(), "#L", line!());
+
+    external! { concat!(); }
+    with_span! {
+        span
+        concat!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/useless_concat.rs b/src/tools/clippy/tests/ui/useless_concat.rs
new file mode 100644
index 00000000000..338d20a48ae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.rs
@@ -0,0 +1,41 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::useless_concat)]
+#![allow(clippy::print_literal)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+macro_rules! my_concat {
+    ($fmt:literal $(, $e:expr)*) => {
+        println!(concat!("ERROR: ", $fmt), $($e,)*);
+    }
+}
+
+fn main() {
+    let x = concat!(); //~ useless_concat
+    let x = concat!('c'); //~ useless_concat
+    let x = concat!('"'); //~ useless_concat
+    let x = concat!(true); //~ useless_concat
+    let x = concat!(1f32); //~ useless_concat
+    let x = concat!(1.0000f32); //~ useless_concat
+    let x = concat!(1_f32); //~ useless_concat
+    let x = concat!(1_); //~ useless_concat
+    let x = concat!(1.0000_f32); //~ useless_concat
+    let x = concat!(1.0000_); //~ useless_concat
+    let x = concat!("a\u{1f600}\n"); //~ useless_concat
+    let x = concat!(r##"a"##); //~ useless_concat
+    let x = concat!(1); //~ useless_concat
+    println!("b: {}", concat!("a")); //~ useless_concat
+    // Should not lint.
+    let x = concat!("a", "b");
+    let local_i32 = 1;
+    my_concat!("{}", local_i32);
+    let x = concat!(file!(), "#L", line!());
+
+    external! { concat!(); }
+    with_span! {
+        span
+        concat!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/useless_concat.stderr b/src/tools/clippy/tests/ui/useless_concat.stderr
new file mode 100644
index 00000000000..43d6d9ff579
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.stderr
@@ -0,0 +1,89 @@
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:16:13
+   |
+LL |     let x = concat!();
+   |             ^^^^^^^^^ help: replace with: `""`
+   |
+   = note: `-D clippy::useless-concat` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_concat)]`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:17:13
+   |
+LL |     let x = concat!('c');
+   |             ^^^^^^^^^^^^ help: replace with: `"c"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:18:13
+   |
+LL |     let x = concat!('"');
+   |             ^^^^^^^^^^^^ help: replace with: `"\""`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:19:13
+   |
+LL |     let x = concat!(true);
+   |             ^^^^^^^^^^^^^ help: replace with: `"true"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:20:13
+   |
+LL |     let x = concat!(1f32);
+   |             ^^^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:21:13
+   |
+LL |     let x = concat!(1.0000f32);
+   |             ^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:22:13
+   |
+LL |     let x = concat!(1_f32);
+   |             ^^^^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:23:13
+   |
+LL |     let x = concat!(1_);
+   |             ^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:24:13
+   |
+LL |     let x = concat!(1.0000_f32);
+   |             ^^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:25:13
+   |
+LL |     let x = concat!(1.0000_);
+   |             ^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:26:13
+   |
+LL |     let x = concat!("a\u{1f600}\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `"a😀\n"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:27:13
+   |
+LL |     let x = concat!(r##"a"##);
+   |             ^^^^^^^^^^^^^^^^^ help: replace with: `"a"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:28:13
+   |
+LL |     let x = concat!(1);
+   |             ^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:29:23
+   |
+LL |     println!("b: {}", concat!("a"));
+   |                       ^^^^^^^^^^^^ help: replace with: `"a"`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index 489caacf212..ad30c94f347 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -427,3 +427,18 @@ mod issue11819 {
         }
     }
 }
+
+fn issue14739() {
+    use std::ops::Range;
+
+    const R: Range<u32> = 2..7;
+
+    R.into_iter().all(|_x| true); // no lint
+
+    R.into_iter().any(|_x| true); // no lint
+
+    R.for_each(|_x| {});
+    //~^ useless_conversion
+    let _ = R.map(|_x| 0);
+    //~^ useless_conversion
+}
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index 4f3a3b00ea2..505afb34000 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -427,3 +427,18 @@ mod issue11819 {
         }
     }
 }
+
+fn issue14739() {
+    use std::ops::Range;
+
+    const R: Range<u32> = 2..7;
+
+    R.into_iter().all(|_x| true); // no lint
+
+    R.into_iter().any(|_x| true); // no lint
+
+    R.into_iter().for_each(|_x| {});
+    //~^ useless_conversion
+    let _ = R.into_iter().map(|_x| 0);
+    //~^ useless_conversion
+}
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index 3cde2a786e4..3bfaf1411c2 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -377,5 +377,17 @@ LL -             takes_into_iter(self.my_field.into_iter());
 LL +             takes_into_iter(&mut *self.my_field);
    |
 
-error: aborting due to 41 previous errors
+error: useless conversion to the same type: `std::ops::Range<u32>`
+  --> tests/ui/useless_conversion.rs:440:5
+   |
+LL |     R.into_iter().for_each(|_x| {});
+   |     ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
+
+error: useless conversion to the same type: `std::ops::Range<u32>`
+  --> tests/ui/useless_conversion.rs:442:13
+   |
+LL |     let _ = R.into_iter().map(|_x| 0);
+   |             ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
+
+error: aborting due to 43 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
index 4beeef421f3..dcbfd16843d 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
@@ -71,6 +71,27 @@ fn test2(map: HashMap<String, usize>, key: &str) -> HashMap<String, usize> {
     todo!();
 }
 
+fn issue14822() {
+    trait Trait {
+        type T;
+    }
+    struct S<T: Trait>(T::T);
+
+    // The `delay_bug` happens when evaluating the pointer metadata of `S<T>` which depends on
+    // whether `T::T` is `Sized`. Since the type alias doesn't have a trait bound of `T: Trait`
+    // evaluating `T::T: Sized` ultimately fails with `NoSolution`.
+    type A<T> = HashMap<u32, *const S<T>>;
+    type B<T> = HashMap<u32, S<T>>;
+
+    enum E {}
+    impl Trait for E {
+        type T = ();
+    }
+    type C = HashMap<u32, *const S<E>>;
+    type D = HashMap<u32, S<E>>;
+    //~^ zero_sized_map_values
+}
+
 fn main() {
     let _: HashMap<String, ()> = HashMap::new();
     //~^ zero_sized_map_values
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
index ed8536acfe8..d29491fa05c 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
@@ -81,7 +81,15 @@ LL | fn test(map: HashMap<String, ()>, key: &str) -> HashMap<String, ()> {
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:75:34
+  --> tests/ui/zero_sized_hashmap_values.rs:91:14
+   |
+LL |     type D = HashMap<u32, S<E>>;
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a set instead
+
+error: map with zero-sized value type
+  --> tests/ui/zero_sized_hashmap_values.rs:96:34
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |                                  ^^^^^^^
@@ -89,7 +97,7 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:75:12
+  --> tests/ui/zero_sized_hashmap_values.rs:96:12
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |            ^^^^^^^^^^^^^^^^^^^
@@ -97,12 +105,12 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:81:12
+  --> tests/ui/zero_sized_hashmap_values.rs:102:12
    |
 LL |     let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect();
    |            ^^^^^^^^^^^^^
    |
    = help: consider using a set instead
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index eb2f9f9dd61..389f22c6a2c 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -1,7 +1,7 @@
 [relabel]
 allow-unauthenticated = [
     "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*",
-    "good-first-issue", "beta-nominated"
+    "good first issue", "beta-nominated"
 ]
 
 # Allows shortcuts like `@rustbot ready`
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index b692ddab4ff..de521393cd0 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -218,7 +218,7 @@ degree documented below):
   make no promises and we don't run tests for such targets.
 - We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
   - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
-  - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
+  - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
   - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
@@ -580,6 +580,7 @@ Definite bugs found:
 * [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281)
 * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
 * [Mockall reading unintialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
+* [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
 
 Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
 
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index bd4ca2860f3..c1915ae617e 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -208,9 +208,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.4"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38"
+checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0"
 dependencies = [
  "anyhow",
  "rustc_version",
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 23048914af1..5c579b2a77d 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "6"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.19"
-rustc-build-sysroot = "0.5.4"
+rustc-build-sysroot = "0.5.7"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 755e02d02ec..9ae15739dcb 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -156,16 +156,17 @@ case $HOST_TARGET in
     MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
     MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
     # Extra tier 2
-    TEST_TARGET=arm-unknown-linux-gnueabi run_tests
-    TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests
+    MANY_SEEDS=16 TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
     # Not officially supported tier 2
-    TEST_TARGET=x86_64-unknown-illumos run_tests
-    TEST_TARGET=x86_64-pc-solaris run_tests
+    MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics
+    MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests
+    MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests
     # Partially supported targets (tier 2)
     BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
     UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
-    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
-    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd
     TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8b98fe3c4fc..46989695302 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ac17c3486c6fdfbb0c3c18b99f3d8dfbff625d29
+2b96ddca1272960623e41829439df8dae82d20af
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index dd389d97cdc..21bd7fb54c6 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -168,7 +168,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 AllocKind::Dead => unreachable!(),
             };
             // We don't have to expose this pointer yet, we do that in `prepare_for_native_call`.
-            return interp_ok(base_ptr.addr().try_into().unwrap());
+            return interp_ok(base_ptr.addr().to_u64());
         }
         // We are not in native lib mode, so we control the addresses ourselves.
         if let Some((reuse_addr, clock)) = global_state.reuse.take_addr(
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index 29d4f2bb7b0..ab6aaed5e3e 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -4,6 +4,7 @@ use rand::Rng;
 use rustc_abi::{Align, Size};
 
 use crate::concurrency::VClock;
+use crate::helpers::ToUsize as _;
 use crate::{MemoryKind, MiriConfig, ThreadId};
 
 const MAX_POOL_SIZE: usize = 64;
@@ -46,7 +47,7 @@ impl ReusePool {
     }
 
     fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> {
-        let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap();
+        let pool_idx: usize = align.bytes().trailing_zeros().to_usize();
         if self.pool.len() <= pool_idx {
             self.pool.resize(pool_idx + 1, Vec::new());
         }
diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs
index 69ede279aa9..6788494c01c 100644
--- a/src/tools/miri/src/alloc_bytes.rs
+++ b/src/tools/miri/src/alloc_bytes.rs
@@ -5,6 +5,8 @@ use std::{alloc, slice};
 use rustc_abi::{Align, Size};
 use rustc_middle::mir::interpret::AllocBytes;
 
+use crate::helpers::ToU64 as _;
+
 /// Allocation bytes that explicitly handle the layout of the data they're storing.
 /// This is necessary to interface with native code that accesses the program store in Miri.
 #[derive(Debug)]
@@ -21,7 +23,7 @@ pub struct MiriAllocBytes {
 impl Clone for MiriAllocBytes {
     fn clone(&self) -> Self {
         let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
-        let align = Align::from_bytes(self.layout.align().try_into().unwrap()).unwrap();
+        let align = Align::from_bytes(self.layout.align().to_u64()).unwrap();
         MiriAllocBytes::from_bytes(bytes, align)
     }
 }
@@ -90,7 +92,7 @@ impl AllocBytes for MiriAllocBytes {
         let align = align.bytes();
         // SAFETY: `alloc_fn` will only be used with `size != 0`.
         let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
-        let alloc_bytes = MiriAllocBytes::alloc_with(size.try_into().unwrap(), align, alloc_fn)
+        let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, alloc_fn)
             .unwrap_or_else(|()| {
                 panic!("Miri ran out of memory: cannot create allocation of {size} bytes")
             });
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index 7874721c0ac..dcd5a6cb023 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -17,6 +17,8 @@ use std::mem;
 
 use rustc_data_structures::fx::FxHashMap;
 
+use crate::helpers::ToUsize;
+
 /// Intermediate key between a UniKeyMap and a UniValMap.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct UniIndex {
@@ -158,7 +160,7 @@ where
 impl<V> UniValMap<V> {
     /// Whether this index has an associated value.
     pub fn contains_idx(&self, idx: UniIndex) -> bool {
-        self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some()
+        self.data.get(idx.idx.to_usize()).and_then(Option::as_ref).is_some()
     }
 
     /// Reserve enough space to insert the value at the right index.
@@ -174,29 +176,29 @@ impl<V> UniValMap<V> {
 
     /// Assign a value to the index. Permanently overwrites any previous value.
     pub fn insert(&mut self, idx: UniIndex, val: V) {
-        self.extend_to_length(idx.idx as usize + 1);
-        self.data[idx.idx as usize] = Some(val)
+        self.extend_to_length(idx.idx.to_usize() + 1);
+        self.data[idx.idx.to_usize()] = Some(val)
     }
 
     /// Get the value at this index, if it exists.
     pub fn get(&self, idx: UniIndex) -> Option<&V> {
-        self.data.get(idx.idx as usize).and_then(Option::as_ref)
+        self.data.get(idx.idx.to_usize()).and_then(Option::as_ref)
     }
 
     /// Get the value at this index mutably, if it exists.
     pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> {
-        self.data.get_mut(idx.idx as usize).and_then(Option::as_mut)
+        self.data.get_mut(idx.idx.to_usize()).and_then(Option::as_mut)
     }
 
     /// Delete any value associated with this index.
     /// Returns None if the value was not present, otherwise
     /// returns the previously stored value.
     pub fn remove(&mut self, idx: UniIndex) -> Option<V> {
-        if idx.idx as usize >= self.data.len() {
+        if idx.idx.to_usize() >= self.data.len() {
             return None;
         }
         let mut res = None;
-        mem::swap(&mut res, &mut self.data[idx.idx as usize]);
+        mem::swap(&mut res, &mut self.data[idx.idx.to_usize()]);
         res
     }
 }
@@ -209,8 +211,8 @@ pub struct UniEntry<'a, V> {
 impl<'a, V> UniValMap<V> {
     /// Get a wrapper around a mutable access to the value corresponding to `idx`.
     pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> {
-        self.extend_to_length(idx.idx as usize + 1);
-        UniEntry { inner: &mut self.data[idx.idx as usize] }
+        self.extend_to_length(idx.idx.to_usize() + 1);
+        UniEntry { inner: &mut self.data[idx.idx.to_usize()] }
     }
 }
 
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
index b47b614cf5f..9583de5a483 100644
--- a/src/tools/miri/src/concurrency/cpu_affinity.rs
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -25,7 +25,7 @@ impl CpuAffinityMask {
         let mut this = Self([0; Self::CPU_MASK_BYTES]);
 
         // the default affinity mask includes only the available CPUs
-        for i in 0..cpu_count as usize {
+        for i in 0..cpu_count.to_usize() {
             this.set(cx, i);
         }
 
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index dd33f90f153..17d0f3f5ff6 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -9,7 +9,7 @@ mod vector_clock;
 pub mod weak_memory;
 
 // Import either the real genmc adapter or a dummy module.
-cfg_match! {
+cfg_select! {
     feature = "genmc" => {
         mod genmc;
         pub use self::genmc::{GenmcCtx, GenmcConfig};
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index 78858fcedae..494e7922d2b 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -7,6 +7,7 @@ use rustc_span::{DUMMY_SP, Span, SpanData};
 use smallvec::SmallVec;
 
 use super::data_race::NaReadType;
+use crate::helpers::ToUsize;
 
 /// A vector clock index, this is associated with a thread id
 /// but in some cases one vector index may be shared with
@@ -157,7 +158,7 @@ impl VClock {
 
     #[inline]
     pub(super) fn index_mut(&mut self, index: VectorIdx) -> &mut VTimestamp {
-        self.0.as_mut_slice().get_mut(index.to_u32() as usize).unwrap()
+        self.0.as_mut_slice().get_mut(index.to_u32().to_usize()).unwrap()
     }
 
     /// Get a mutable slice to the internal vector with minimum `min_len`
@@ -420,7 +421,7 @@ impl Index<VectorIdx> for VClock {
 
     #[inline]
     fn index(&self, index: VectorIdx) -> &VTimestamp {
-        self.as_slice().get(index.to_u32() as usize).unwrap_or(&VTimestamp::ZERO)
+        self.as_slice().get(index.to_u32().to_usize()).unwrap_or(&VTimestamp::ZERO)
     }
 }
 
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 8e7c9edfcc0..ff2ec1b3e60 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1412,3 +1412,26 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
         u32::try_from(len).unwrap()
     }
 }
+
+/// We don't support 16-bit systems, so let's have ergonomic conversion from `u32` to `usize`.
+pub trait ToUsize {
+    fn to_usize(self) -> usize;
+}
+
+impl ToUsize for u32 {
+    fn to_usize(self) -> usize {
+        self.try_into().unwrap()
+    }
+}
+
+/// Similarly, a maximum address size of `u64` is assumed widely here, so let's have ergonomic
+/// converion from `usize` to `u64`.
+pub trait ToU64 {
+    fn to_u64(self) -> u64;
+}
+
+impl ToU64 for usize {
+    fn to_u64(self) -> u64 {
+        self.try_into().unwrap()
+    }
+}
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index c9250ba1b81..b17fd4fb7f9 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -634,7 +634,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let index_len = index.len();
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(index_len as u64, dest_len);
+                assert_eq!(u64::try_from(index_len).unwrap(), dest_len);
 
                 for i in 0..dest_len {
                     let src_index: u64 =
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 0b7a067058b..9d663ca9edf 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,5 @@
 #![feature(rustc_private)]
-#![feature(cfg_match)]
+#![feature(cfg_select)]
 #![feature(float_gamma)]
 #![feature(float_erf)]
 #![feature(map_try_insert)]
@@ -41,14 +41,7 @@
     rustc::potential_query_instability,
     rustc::untranslatable_diagnostic,
 )]
-#![warn(
-    rust_2018_idioms,
-    unqualified_local_imports,
-    clippy::cast_possible_wrap, // unsigned -> signed
-    clippy::cast_sign_loss, // signed -> unsigned
-    clippy::cast_lossless,
-    clippy::cast_possible_truncation,
-)]
+#![warn(rust_2018_idioms, unqualified_local_imports, clippy::as_conversions)]
 // Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
 #![recursion_limit = "256"]
 
@@ -60,7 +53,7 @@ extern crate tracing;
 extern crate rustc_abi;
 extern crate rustc_apfloat;
 extern crate rustc_ast;
-extern crate rustc_attr_parsing;
+extern crate rustc_attr_data_structures;
 extern crate rustc_const_eval;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
@@ -140,7 +133,7 @@ pub use crate::eval::{
     AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
     ValidationMode, create_ecx, eval_entry,
 };
-pub use crate::helpers::{AccessKind, EvalContextExt as _};
+pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _};
 pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
     AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index dbde415170c..f75adffd950 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -13,7 +13,7 @@ use rand::rngs::StdRng;
 use rand::{Rng, SeedableRng};
 use rustc_abi::{Align, ExternAbi, Size};
 use rustc_apfloat::{Float, FloatConvert};
-use rustc_attr_parsing::InlineAttr;
+use rustc_attr_data_structures::InlineAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
 use rustc_data_structures::static_assert_size;
@@ -544,9 +544,6 @@ pub struct MiriMachine<'tcx> {
     /// Failure rate of compare_exchange_weak, between 0.0 and 1.0
     pub(crate) cmpxchg_weak_failure_rate: f64,
 
-    /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded.
-    pub(crate) mute_stdout_stderr: bool,
-
     /// The probability of the active thread being preempted at the end of each basic block.
     pub(crate) preemption_rate: f64,
 
@@ -722,7 +719,6 @@ impl<'tcx> MiriMachine<'tcx> {
             track_alloc_accesses: config.track_alloc_accesses,
             check_alignment: config.check_alignment,
             cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
-            mute_stdout_stderr: config.mute_stdout_stderr,
             preemption_rate: config.preemption_rate,
             report_progress: config.report_progress,
             basic_block_count: 0,
@@ -925,7 +921,6 @@ impl VisitProvenance for MiriMachine<'_> {
             track_alloc_accesses: _,
             check_alignment: _,
             cmpxchg_weak_failure_rate: _,
-            mute_stdout_stderr: _,
             preemption_rate: _,
             report_progress: _,
             basic_block_count: _,
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 7e667e70a17..9f3bc06771f 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -25,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let frame_count = this.active_thread_stack().len();
 
-        this.write_scalar(Scalar::from_target_usize(frame_count.try_into().unwrap(), this), dest)
+        this.write_scalar(Scalar::from_target_usize(frame_count.to_u64(), this), dest)
     }
 
     fn handle_miri_get_backtrace(
@@ -70,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             1 =>
                 for (i, ptr) in ptrs.into_iter().enumerate() {
-                    let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap();
+                    let offset = ptr_layout.size.checked_mul(i.to_u64(), this).unwrap();
 
                     let op_place = buf_place.offset(offset, ptr_layout, this)?;
 
@@ -158,11 +158,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             1 => {
                 this.write_scalar(
-                    Scalar::from_target_usize(name.len().try_into().unwrap(), this),
+                    Scalar::from_target_usize(name.len().to_u64(), this),
                     &this.project_field(dest, 0)?,
                 )?;
                 this.write_scalar(
-                    Scalar::from_target_usize(filename.len().try_into().unwrap(), this),
+                    Scalar::from_target_usize(filename.len().to_u64(), this),
                     &this.project_field(dest, 1)?,
                 )?;
             }
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 42603e784bb..31142431247 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -135,7 +135,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
 
     /// Reads as much as possible into the given buffer `ptr`.
     /// `len` indicates how many bytes we should try to read.
-    /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
+    ///
+    /// When the read is done, `finish` will be called. Note that `read` itself may return before
+    /// that happens! Everything that should happen "after" the `read` needs to happen inside
+    /// `finish`.
     fn read<'tcx>(
         self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
@@ -149,7 +152,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
 
     /// Writes as much as possible from the given buffer `ptr`.
     /// `len` indicates how many bytes we should try to write.
-    /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
+    ///
+    /// When the write is done, `finish` will be called. Note that `write` itself may return before
+    /// that happens! Everything that should happen "after" the `write` needs to happen inside
+    /// `finish`.
     fn write<'tcx>(
         self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 52c16a0c2e2..a81f459e5e1 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -639,7 +639,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
                 // The docs say val is "interpreted as unsigned char".
-                #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
+                #[expect(clippy::as_conversions)]
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
@@ -665,7 +665,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
                 // The docs say val is "interpreted as unsigned char".
-                #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
+                #[expect(clippy::as_conversions)]
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
@@ -676,7 +676,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     .iter()
                     .position(|&c| c == val);
                 if let Some(idx) = idx {
-                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx as u64), this);
+                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx), this);
                     this.write_pointer(new_ptr, dest)?;
                 } else {
                     this.write_null(dest)?;
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index acf3f74a93d..e597b527cb7 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -1,4 +1,5 @@
 use std::io;
+use std::io::ErrorKind;
 
 use crate::*;
 
@@ -13,6 +14,29 @@ pub enum IoError {
 }
 pub use self::IoError::*;
 
+impl IoError {
+    pub(crate) fn into_ntstatus(self) -> i32 {
+        let raw = match self {
+            HostError(e) =>
+                match e.kind() {
+                    // STATUS_MEDIA_WRITE_PROTECTED
+                    ErrorKind::ReadOnlyFilesystem => 0xC00000A2u32,
+                    // STATUS_FILE_INVALID
+                    ErrorKind::InvalidInput => 0xC0000098,
+                    // STATUS_DISK_FULL
+                    ErrorKind::QuotaExceeded => 0xC000007F,
+                    // STATUS_ACCESS_DENIED
+                    ErrorKind::PermissionDenied => 0xC0000022,
+                    // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
+                    _ => 0xC0000185,
+                },
+            // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
+            _ => 0xC0000185,
+        };
+        raw.cast_signed()
+    }
+}
+
 impl From<io::Error> for IoError {
     fn from(value: io::Error) -> Self {
         IoError::HostError(value)
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index 837e1b31cac..1e6c93333c1 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -92,16 +92,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option<CodePtr> {
         let this = self.eval_context_mut();
         // Try getting the function from the shared library.
-        // On windows `_lib_path` will be unused, hence the name starting with `_`.
-        let (lib, _lib_path) = this.machine.native_lib.as_ref().unwrap();
-        let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe {
-            match lib.get(link_name.as_str().as_bytes()) {
-                Ok(x) => x,
-                Err(_) => {
-                    return None;
-                }
-            }
-        };
+        let (lib, lib_path) = this.machine.native_lib.as_ref().unwrap();
+        let func: libloading::Symbol<'_, unsafe extern "C" fn()> =
+            unsafe { lib.get(link_name.as_str().as_bytes()).ok()? };
+        #[expect(clippy::as_conversions)] // fn-ptr to raw-ptr cast needs `as`.
+        let fn_ptr = *func.deref() as *mut std::ffi::c_void;
 
         // FIXME: this is a hack!
         // The `libloading` crate will automatically load system libraries like `libc`.
@@ -114,23 +109,25 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`,
         // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411
         // using the `libc` crate where this interface is public.
-        let mut info = std::mem::MaybeUninit::<libc::Dl_info>::uninit();
+        let mut info = std::mem::MaybeUninit::<libc::Dl_info>::zeroed();
         unsafe {
-            if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 {
+            if libc::dladdr(fn_ptr, info.as_mut_ptr()) != 0 {
                 let info = info.assume_init();
                 #[cfg(target_os = "cygwin")]
                 let fname_ptr = info.dli_fname.as_ptr();
                 #[cfg(not(target_os = "cygwin"))]
                 let fname_ptr = info.dli_fname;
+                assert!(!fname_ptr.is_null());
                 if std::ffi::CStr::from_ptr(fname_ptr).to_str().unwrap()
-                    != _lib_path.to_str().unwrap()
+                    != lib_path.to_str().unwrap()
                 {
                     return None;
                 }
             }
         }
+
         // Return a pointer to the function.
-        Some(CodePtr(*func.deref() as *mut _))
+        Some(CodePtr(fn_ptr))
     }
 }
 
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index 30ec0aefcbf..aa3a05ead85 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -7,7 +7,7 @@ use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
 use crate::*;
 
-const TASK_COMM_LEN: usize = 16;
+const TASK_COMM_LEN: u64 = 16;
 
 pub fn prctl<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
@@ -38,7 +38,7 @@ pub fn prctl<'tcx>(
             let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?;
             let name = ecx.read_scalar(name)?;
             let thread = ecx.pthread_self()?;
-            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
+            let len = Scalar::from_target_usize(TASK_COMM_LEN, ecx);
             ecx.check_ptr_access(
                 name.to_pointer(ecx)?,
                 Size::from_bytes(TASK_COMM_LEN),
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 21a386b2927..533a741fea3 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Threading
             "pthread_setname_np" => {
                 let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
-                let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
+                let max_len = u64::MAX; // FreeBSD does not seem to have a limit.
                 let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
@@ -56,6 +56,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
+            "cpuset_getaffinity" => {
+                // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
+                let [level, which, id, set_size, mask] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+
+                let level = this.read_scalar(level)?.to_i32()?;
+                let which = this.read_scalar(which)?.to_i32()?;
+                let id = this.read_scalar(id)?.to_i64()?;
+                let set_size = this.read_target_usize(set_size)?; // measured in bytes
+                let mask = this.read_pointer(mask)?;
+
+                let _level_root = this.eval_libc_i32("CPU_LEVEL_ROOT");
+                let _level_cpuset = this.eval_libc_i32("CPU_LEVEL_CPUSET");
+                let level_which = this.eval_libc_i32("CPU_LEVEL_WHICH");
+
+                let _which_tid = this.eval_libc_i32("CPU_WHICH_TID");
+                let which_pid = this.eval_libc_i32("CPU_WHICH_PID");
+                let _which_jail = this.eval_libc_i32("CPU_WHICH_JAIL");
+                let _which_cpuset = this.eval_libc_i32("CPU_WHICH_CPUSET");
+                let _which_irq = this.eval_libc_i32("CPU_WHICH_IRQ");
+
+                // For sched_getaffinity, the current process is identified by -1.
+                // TODO: Use gettid? I'm (LorrensP-2158466) not that familiar with this api .
+                let id = match id {
+                    -1 => this.active_thread(),
+                    _ =>
+                        throw_unsup_format!(
+                            "`cpuset_getaffinity` is only supported with a pid of -1 (indicating the current thread)"
+                        ),
+                };
+
+                if this.ptr_is_null(mask)? {
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
+                }
+                // We only support CPU_LEVEL_WHICH and CPU_WHICH_PID for now.
+                // This is the bare minimum to make the tests pass.
+                else if level != level_which || which != which_pid {
+                    throw_unsup_format!(
+                        "`cpuset_getaffinity` is only supported with `level` set to CPU_LEVEL_WHICH and `which` set to CPU_WHICH_PID."
+                    );
+                } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&id) {
+                    // `cpusetsize` must be large enough to contain the entire CPU mask.
+                    // FreeBSD only uses `cpusetsize` to verify that it's sufficient for the kernel's CPU mask.
+                    // If it's too small, the syscall returns ERANGE.
+                    // If it's large enough, copying the kernel mask to user space is safe, regardless of the actual size.
+                    // See https://github.com/freebsd/freebsd-src/blob/909aa6781340f8c0b4ae01c6366bf1556ee2d1be/sys/kern/kern_cpuset.c#L1985
+                    if set_size < u64::from(this.machine.num_cpus).div_ceil(8) {
+                        this.set_last_error_and_return(LibcError("ERANGE"), dest)?;
+                    } else {
+                        let cpuset = cpuset.clone();
+                        let byte_count =
+                            Ord::min(cpuset.as_slice().len(), set_size.try_into().unwrap());
+                        this.write_bytes_ptr(
+                            mask,
+                            cpuset.as_slice()[..byte_count].iter().copied(),
+                        )?;
+                        this.write_null(dest)?;
+                    }
+                } else {
+                    // `id` is always that of the active thread, so this is currently unreachable.
+                    unreachable!();
+                }
+            }
+
             // Synchronization primitives
             "_umtx_op" => {
                 let [obj, op, val, uaddr, uaddr2] =
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 1f6acff0787..347930c52f2 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -90,7 +90,7 @@ impl UnixFileDescription for FileHandle {
         op: FlockOp,
     ) -> InterpResult<'tcx, io::Result<()>> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        cfg_match! {
+        cfg_select! {
             all(target_family = "unix", not(target_os = "solaris")) => {
                 use std::os::fd::AsRawFd;
 
@@ -121,13 +121,13 @@ impl UnixFileDescription for FileHandle {
                 use std::os::windows::io::AsRawHandle;
 
                 use windows_sys::Win32::Foundation::{
-                    ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE,
+                    ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, TRUE,
                 };
                 use windows_sys::Win32::Storage::FileSystem::{
                     LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile,
                 };
 
-                let fh = self.file.as_raw_handle() as HANDLE;
+                let fh = self.file.as_raw_handle();
 
                 use FlockOp::*;
                 let (ret, lock_nb) = match op {
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index f5da7b0170b..51c2434d68a 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -14,7 +14,7 @@ use crate::*;
 // The documentation of glibc complains that the kernel never exposes
 // TASK_COMM_LEN through the headers, so it's assumed to always be 16 bytes
 // long including a null terminator.
-const TASK_COMM_LEN: usize = 16;
+const TASK_COMM_LEN: u64 = 16;
 
 pub fn is_dyn_sym(name: &str) -> bool {
     matches!(name, "statx")
@@ -96,7 +96,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // In case of glibc, the length of the output buffer must
                 // be not shorter than TASK_COMM_LEN.
                 let len = this.read_scalar(len)?;
-                let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 {
+                let res = if len.to_target_usize(this)? >= TASK_COMM_LEN {
                     match this.pthread_getname_np(
                         this.read_scalar(thread)?,
                         this.read_scalar(name)?,
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 5046e965082..0281bb9f71d 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -186,7 +186,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = match this.pthread_setname_np(
                     thread,
                     this.read_scalar(name)?,
-                    this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
+                    this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
                     /* truncate */ false,
                 )? {
                     ThreadNameResult::Ok => Scalar::from_u32(0),
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 3d990a1a042..4b6615b3ea8 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -86,7 +86,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         thread: Scalar,
         name: Scalar,
-        name_max_len: usize,
+        name_max_len: u64,
         truncate: bool,
     ) -> InterpResult<'tcx, ThreadNameResult> {
         let this = self.eval_context_mut();
@@ -99,9 +99,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut name = this.read_c_str(name)?.to_owned();
 
         // Comparing with `>=` to account for null terminator.
-        if name.len() >= name_max_len {
+        if name.len().to_u64() >= name_max_len {
             if truncate {
-                name.truncate(name_max_len.saturating_sub(1));
+                name.truncate(name_max_len.saturating_sub(1).try_into().unwrap());
             } else {
                 return interp_ok(ThreadNameResult::NameTooLong);
             }
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index 1b2ccd99ef9..a7c26d601e5 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -230,7 +230,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(match directories::UserDirs::new() {
             Some(dirs) => {
                 let home = dirs.home_dir();
-                let size_avail = if this.ptr_is_null(size.ptr())? {
+                let size_avail = if this.ptr_is_null(buf)? {
                     0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length
                 } else {
                     this.read_scalar(&size)?.to_u32()?
@@ -238,8 +238,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Of course we cannot use `windows_check_buffer_size` here since this uses
                 // a different method for dealing with a too-small buffer than the other functions...
                 let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?;
-                // The Windows docs just say that this is written on failure. But std
-                // seems to rely on it always being written.
+                // As per <https://github.com/MicrosoftDocs/sdk-api/pull/1810>, the size is always
+                // written, not just on failure.
                 this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?;
                 if success {
                     Scalar::from_i32(1) // return TRUE
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index c80858c6363..d822dd07fcd 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -195,69 +195,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File related shims
             "NtWriteFile" => {
-                if !this.frame_in_std() {
-                    throw_unsup_format!(
-                        "`NtWriteFile` support is crude and just enough for stdout to work"
-                    );
-                }
-
                 let [
                     handle,
-                    _event,
-                    _apc_routine,
-                    _apc_context,
+                    event,
+                    apc_routine,
+                    apc_context,
                     io_status_block,
                     buf,
                     n,
                     byte_offset,
-                    _key,
+                    key,
                 ] = this.check_shim(abi, sys_conv, link_name, args)?;
-                let handle = this.read_target_isize(handle)?;
-                let buf = this.read_pointer(buf)?;
-                let n = this.read_scalar(n)?.to_u32()?;
-                let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
-                let io_status_block = this
-                    .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
-
-                if byte_offset != 0 {
-                    throw_unsup_format!(
-                        "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
-                    );
-                }
-
-                let written = if handle == -11 || handle == -12 {
-                    // stdout/stderr
-                    use io::Write;
-
-                    let buf_cont =
-                        this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
-                    let res = if this.machine.mute_stdout_stderr {
-                        Ok(buf_cont.len())
-                    } else if handle == -11 {
-                        io::stdout().write(buf_cont)
-                    } else {
-                        io::stderr().write(buf_cont)
-                    };
-                    // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
-                    res.ok().map(|n| u32::try_from(n).unwrap())
-                } else {
-                    throw_unsup_format!(
-                        "on Windows, writing to anything except stdout/stderr is not supported"
-                    )
-                };
-                // We have to put the result into io_status_block.
-                if let Some(n) = written {
-                    let io_status_information =
-                        this.project_field_named(&io_status_block, "Information")?;
-                    this.write_scalar(
-                        Scalar::from_target_usize(n.into(), this),
-                        &io_status_information,
-                    )?;
-                }
-                // Return whether this was a success. >= 0 is success.
-                // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
-                this.write_scalar(
-                    Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
+                this.NtWriteFile(
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
+                    dest,
+                )?;
+            }
+            "NtReadFile" => {
+                let [
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
+                ] = this.check_shim(abi, sys_conv, link_name, args)?;
+                this.NtReadFile(
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
                     dest,
                 )?;
             }
@@ -322,6 +305,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = this.DeleteFileW(file_name)?;
                 this.write_scalar(res, dest)?;
             }
+            "SetFilePointerEx" => {
+                let [file, distance_to_move, new_file_pointer, move_method] =
+                    this.check_shim(abi, sys_conv, link_name, args)?;
+                let res =
+                    this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
+                this.write_scalar(res, dest)?;
+            }
 
             // Allocation
             "HeapAlloc" => {
@@ -700,12 +690,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "GetStdHandle" => {
                 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
-                let which = this.read_scalar(which)?.to_i32()?;
-                // We just make this the identity function, so we know later in `NtWriteFile` which
-                // one it is. This is very fake, but libtest needs it so we cannot make it a
-                // std-only shim.
-                // FIXME: this should return real HANDLEs when io support is added
-                this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
+                let res = this.GetStdHandle(which)?;
+                this.write_scalar(res, dest)?;
             }
             "CloseHandle" => {
                 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs
index 7561bf45219..72e016c12e9 100644
--- a/src/tools/miri/src/shims/windows/fs.rs
+++ b/src/tools/miri/src/shims/windows/fs.rs
@@ -1,5 +1,6 @@
 use std::fs::{Metadata, OpenOptions};
 use std::io;
+use std::io::SeekFrom;
 use std::path::PathBuf;
 use std::time::SystemTime;
 
@@ -390,6 +391,267 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
     }
+
+    fn NtWriteFile(
+        &mut self,
+        handle: &OpTy<'tcx>,          // HANDLE
+        event: &OpTy<'tcx>,           // HANDLE
+        apc_routine: &OpTy<'tcx>,     // PIO_APC_ROUTINE
+        apc_ctx: &OpTy<'tcx>,         // PVOID
+        io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK
+        buf: &OpTy<'tcx>,             // PVOID
+        n: &OpTy<'tcx>,               // ULONG
+        byte_offset: &OpTy<'tcx>,     // PLARGE_INTEGER
+        key: &OpTy<'tcx>,             // PULONG
+        dest: &MPlaceTy<'tcx>,        // return type: NTSTATUS
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_mut();
+        let handle = this.read_handle(handle, "NtWriteFile")?;
+        let event = this.read_handle(event, "NtWriteFile")?;
+        let apc_routine = this.read_pointer(apc_routine)?;
+        let apc_ctx = this.read_pointer(apc_ctx)?;
+        let buf = this.read_pointer(buf)?;
+        let count = this.read_scalar(n)?.to_u32()?;
+        let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null
+        let key = this.read_pointer(key)?;
+        let io_status_block =
+            this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
+
+        if event != Handle::Null {
+            throw_unsup_format!(
+                "`NtWriteFile` `Event` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_routine)? {
+            throw_unsup_format!(
+                "`NtWriteFile` `ApcRoutine` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_ctx)? {
+            throw_unsup_format!(
+                "`NtWriteFile` `ApcContext` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if byte_offset != 0 {
+            throw_unsup_format!(
+                "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(key)? {
+            throw_unsup_format!("`NtWriteFile` `Key` parameter is non-null, which is unsupported");
+        }
+
+        let fd = match handle {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("NtWriteFile")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtWriteFile")? };
+
+        // Windows writes the output code to IO_STATUS_BLOCK.Status, and number of bytes written
+        // to IO_STATUS_BLOCK.Information.
+        // The status block value and the returned value don't need to match - but
+        // for the cases implemented by miri so far, we can choose to decide that they do.
+        let io_status = {
+            let anon = this.project_field_named(&io_status_block, "Anonymous")?;
+            this.project_field_named(&anon, "Status")?
+        };
+        let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+
+        let finish = {
+            let io_status = io_status.clone();
+            let io_status_info = io_status_info.clone();
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: u32,
+                    io_status: MPlaceTy<'tcx>,
+                    io_status_info: MPlaceTy<'tcx>,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(read_size) => {
+                            assert!(read_size <= count.try_into().unwrap());
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?;
+                            this.write_int(0, &io_status)?;
+                            this.write_int(0, &dest)
+                        }
+                        Err(e) => {
+                            this.write_int(0, &io_status_info)?;
+                            let status = e.into_ntstatus();
+                            this.write_int(status, &io_status)?;
+                            this.write_int(status, &dest)
+                        }
+                }}
+            )
+        };
+
+        desc.write(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
+
+        // Return status is written to `dest` and `io_status_block` on callback completion.
+        interp_ok(())
+    }
+
+    fn NtReadFile(
+        &mut self,
+        handle: &OpTy<'tcx>,          // HANDLE
+        event: &OpTy<'tcx>,           // HANDLE
+        apc_routine: &OpTy<'tcx>,     // PIO_APC_ROUTINE
+        apc_ctx: &OpTy<'tcx>,         // PVOID
+        io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK
+        buf: &OpTy<'tcx>,             // PVOID
+        n: &OpTy<'tcx>,               // ULONG
+        byte_offset: &OpTy<'tcx>,     // PLARGE_INTEGER
+        key: &OpTy<'tcx>,             // PULONG
+        dest: &MPlaceTy<'tcx>,        // return type: NTSTATUS
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_mut();
+        let handle = this.read_handle(handle, "NtReadFile")?;
+        let event = this.read_handle(event, "NtReadFile")?;
+        let apc_routine = this.read_pointer(apc_routine)?;
+        let apc_ctx = this.read_pointer(apc_ctx)?;
+        let buf = this.read_pointer(buf)?;
+        let count = this.read_scalar(n)?.to_u32()?;
+        let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null
+        let key = this.read_pointer(key)?;
+        let io_status_block =
+            this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
+
+        if event != Handle::Null {
+            throw_unsup_format!("`NtReadFile` `Event` parameter is non-null, which is unsupported");
+        }
+
+        if !this.ptr_is_null(apc_routine)? {
+            throw_unsup_format!(
+                "`NtReadFile` `ApcRoutine` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_ctx)? {
+            throw_unsup_format!(
+                "`NtReadFile` `ApcContext` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if byte_offset != 0 {
+            throw_unsup_format!(
+                "`NtReadFile` `ByteOffset` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(key)? {
+            throw_unsup_format!("`NtReadFile` `Key` parameter is non-null, which is unsupported");
+        }
+
+        // See NtWriteFile above for commentary on this
+        let io_status = {
+            let anon = this.project_field_named(&io_status_block, "Anonymous")?;
+            this.project_field_named(&anon, "Status")?
+        };
+        let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+
+        let finish = {
+            let io_status = io_status.clone();
+            let io_status_info = io_status_info.clone();
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: u32,
+                    io_status: MPlaceTy<'tcx>,
+                    io_status_info: MPlaceTy<'tcx>,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(read_size) => {
+                            assert!(read_size <= count.try_into().unwrap());
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?;
+                            this.write_int(0, &io_status)?;
+                            this.write_int(0, &dest)
+                        }
+                        Err(e) => {
+                            this.write_int(0, &io_status_info)?;
+                            let status = e.into_ntstatus();
+                            this.write_int(status, &io_status)?;
+                            this.write_int(status, &dest)
+                        }
+                }}
+            )
+        };
+
+        let fd = match handle {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("NtWriteFile")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtReadFile")? };
+
+        desc.read(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
+
+        // See NtWriteFile for commentary on this
+        interp_ok(())
+    }
+
+    fn SetFilePointerEx(
+        &mut self,
+        file: &OpTy<'tcx>,         // HANDLE
+        dist_to_move: &OpTy<'tcx>, // LARGE_INTEGER
+        new_fp: &OpTy<'tcx>,       // PLARGE_INTEGER
+        move_method: &OpTy<'tcx>,  // DWORD
+    ) -> InterpResult<'tcx, Scalar> {
+        // ^ Returns BOOL (i32 on Windows)
+        let this = self.eval_context_mut();
+        let file = this.read_handle(file, "SetFilePointerEx")?;
+        let dist_to_move = this.read_scalar(dist_to_move)?.to_i64()?;
+        let new_fp_ptr = this.read_pointer(new_fp)?;
+        let move_method = this.read_scalar(move_method)?.to_u32()?;
+
+        let fd = match file {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("SetFilePointerEx")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else {
+            throw_unsup_format!("`SetFilePointerEx` is only supported on file backed handles");
+        };
+
+        let file_begin = this.eval_windows_u32("c", "FILE_BEGIN");
+        let file_current = this.eval_windows_u32("c", "FILE_CURRENT");
+        let file_end = this.eval_windows_u32("c", "FILE_END");
+
+        let seek = if move_method == file_begin {
+            SeekFrom::Start(dist_to_move.try_into().unwrap())
+        } else if move_method == file_current {
+            SeekFrom::Current(dist_to_move)
+        } else if move_method == file_end {
+            SeekFrom::End(dist_to_move)
+        } else {
+            throw_unsup_format!("Invalid move method: {move_method}")
+        };
+
+        match desc.seek(this.machine.communicate(), seek)? {
+            Ok(n) => {
+                if !this.ptr_is_null(new_fp_ptr)? {
+                    this.write_scalar(
+                        Scalar::from_i64(n.try_into().unwrap()),
+                        &this.deref_pointer_as(new_fp, this.machine.layouts.i64)?,
+                    )?;
+                }
+                interp_ok(this.eval_windows("c", "TRUE"))
+            }
+            Err(e) => {
+                this.set_last_error(e)?;
+                interp_ok(this.eval_windows("c", "FALSE"))
+            }
+        }
+    }
 }
 
 /// Windows FILETIME is measured in 100-nanosecs since 1601
@@ -401,7 +663,7 @@ fn extract_windows_epoch<'tcx>(
         Some(time) => {
             let duration = ecx.system_time_since_windows_epoch(&time)?;
             let duration_ticks = ecx.windows_ticks_for(duration)?;
-            #[allow(clippy::cast_possible_truncation)]
+            #[expect(clippy::as_conversions)]
             interp_ok(Some((duration_ticks as u32, (duration_ticks >> 32) as u32)))
         }
         None => interp_ok(None),
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index eec6c62bebc..5c04271fac5 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -70,8 +70,7 @@ impl Handle {
             Self::Null => 0,
             Self::Pseudo(pseudo_handle) => pseudo_handle.value(),
             Self::Thread(thread) => thread.to_u32(),
-            #[expect(clippy::cast_sign_loss)]
-            Self::File(fd) => fd as u32,
+            Self::File(fd) => fd.cast_unsigned(),
             // INVALID_HANDLE_VALUE is -1. This fact is explicitly declared or implied in several
             // pages of Windows documentation.
             // 1: https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle?view=net-9.0
@@ -124,11 +123,10 @@ impl Handle {
             Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null),
             Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)),
             Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))),
-            #[expect(clippy::cast_possible_wrap)]
             Self::FILE_DISCRIMINANT => {
                 // This cast preserves all bits.
                 assert_eq!(size_of_val(&data), size_of::<FdNum>());
-                Some(Self::File(data as FdNum))
+                Some(Self::File(data.cast_signed()))
             }
             Self::INVALID_DISCRIMINANT => Some(Self::Invalid),
             _ => None,
@@ -156,8 +154,7 @@ impl Handle {
     pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar {
         // 64-bit handles are sign extended 32-bit handles
         // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
-        #[expect(clippy::cast_possible_wrap)] // we want it to wrap
-        let signed_handle = self.to_packed() as i32;
+        let signed_handle = self.to_packed().cast_signed();
         Scalar::from_target_isize(signed_handle.into(), cx)
     }
 
@@ -171,9 +168,8 @@ impl Handle {
     ) -> InterpResult<'tcx, Result<Self, HandleError>> {
         let sign_extended_handle = handle.to_target_isize(cx)?;
 
-        #[expect(clippy::cast_sign_loss)] // we want to lose the sign
         let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) {
-            signed_handle as u32
+            signed_handle.cast_unsigned()
         } else {
             // if a handle doesn't fit in an i32, it isn't valid.
             return interp_ok(Err(HandleError::InvalidHandle));
@@ -224,6 +220,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )))
     }
 
+    fn GetStdHandle(&mut self, which: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let which = this.read_scalar(which)?.to_i32()?;
+
+        let stdin = this.eval_windows("c", "STD_INPUT_HANDLE").to_i32()?;
+        let stdout = this.eval_windows("c", "STD_OUTPUT_HANDLE").to_i32()?;
+        let stderr = this.eval_windows("c", "STD_ERROR_HANDLE").to_i32()?;
+
+        // These values don't mean anything on Windows, but Miri unconditionally sets them up to the
+        // unix in/out/err descriptors. So we take advantage of that.
+        // Due to the `Handle` encoding, these values will not be directly exposed to the user.
+        let fd_num = if which == stdin {
+            0
+        } else if which == stdout {
+            1
+        } else if which == stderr {
+            2
+        } else {
+            throw_unsup_format!("Invalid argument to `GetStdHandle`: {which}")
+        };
+        let handle = Handle::File(fd_num);
+        interp_ok(handle.to_scalar(this))
+    }
+
     fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
index 4774ec9f9d8..a91c74283fd 100644
--- a/src/tools/miri/src/shims/x86/gfni.rs
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -133,12 +133,12 @@ fn affine_transform<'tcx>(
 // This is a evaluated at compile time. Trait based conversion is not available.
 /// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for the
 /// definition of `gf_inv` which was used for the creation of this table.
-#[expect(clippy::cast_possible_truncation)]
 static TABLE: [u8; 256] = {
     let mut array = [0; 256];
 
     let mut i = 1;
     while i < 256 {
+        #[expect(clippy::as_conversions)] // no `try_from` in const...
         let mut x = i as u8;
         let mut y = gf2p8_mul(x, x);
         x = y;
@@ -160,7 +160,7 @@ static TABLE: [u8; 256] = {
 /// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
 /// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for details.
 // This is a const function. Trait based conversion is not available.
-#[expect(clippy::cast_possible_truncation)]
+#[expect(clippy::as_conversions)]
 const fn gf2p8_mul(left: u8, right: u8) -> u8 {
     // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide.
     // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index e57217dc6f2..ac59cc2dfeb 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1110,7 +1110,7 @@ fn pmulhrsw<'tcx>(
 
         // The result of this operation can overflow a signed 16-bit integer.
         // When `left` and `right` are -0x8000, the result is 0x8000.
-        #[expect(clippy::cast_possible_truncation)]
+        #[expect(clippy::as_conversions)]
         let res = res as i16;
 
         ecx.write_scalar(Scalar::from_i16(res), &dest)?;
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
index 6d2c151243c..23c83553f3b 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -43,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // We reverse the order because x86 is little endian but the copied implementation uses
             // big endian.
             for (i, part) in val.into_iter().rev().enumerate() {
-                let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
+                let projected = &ecx.project_index(dest, i.to_u64())?;
                 ecx.write_scalar(Scalar::from_u32(part), projected)?;
             }
             interp_ok(())
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 02336a722f7..66bff328626 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -440,7 +440,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let crc = if bit_size == 64 {
                     // The 64-bit version will only consider the lower 32 bits,
                     // while the upper 32 bits get discarded.
-                    #[expect(clippy::cast_possible_truncation)]
+                    #[expect(clippy::as_conversions)]
                     u128::from((left.to_u64()? as u32).reverse_bits())
                 } else {
                     u128::from(left.to_u32()?.reverse_bits())
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 653228a5e3d..fa833b51fa3 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -25,6 +25,13 @@ page_size = "0.6"
 tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] }
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security"] }
+windows-sys = { version = "0.59", features = [
+    "Win32_Foundation",
+    "Win32_System_Threading",
+    "Win32_Storage_FileSystem",
+    "Win32_Security",
+    "Win32_System_IO",
+    "Wdk_Storage_FileSystem",
+] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
deleted file mode 100644
index 3ef194c5c71..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ignore-target: windows # No libc IO on Windows
-
-fn main() -> std::io::Result<()> {
-    let mut bytes = [0u8; 512];
-    unsafe {
-        libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled
-    }
-    Ok(())
-}
diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
index 42c3a9619d4..2c01b0132b8 100644
--- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
+++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
@@ -2,6 +2,7 @@
 //@compile-flags: -Zmiri-disable-stacked-borrows
 // Needs atomic accesses larger than the pointer size
 //@ignore-bitwidth: 64
+//@ignore-target: mips-
 
 use std::sync::atomic::{AtomicI64, Ordering};
 
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
index e6282613df7..ff16ac61d8b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
 
 fn main() {
     let mut data = [0u8; 16];
     unsafe {
         let a = data.as_mut_ptr();
         let b = a.wrapping_offset(1) as *mut _;
-        copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
+        // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+        std::intrinsics::copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
index fef5a0a82a0..9b60a48703b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
   --> tests/fail/intrinsics/copy_overlapping.rs:LL:CC
    |
-LL |         copy_nonoverlapping(a, b, 2);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
+LL |         std::intrinsics::copy_nonoverlapping(a, b, 2);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
index ded9d0b669e..311789cdc4b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
 
 fn main() {
     let mut data = [0u16; 8];
     let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16;
     // Even copying 0 elements to something unaligned should error
     unsafe {
-        copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
+        // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+        std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
index 2d0edd4e6cb..65dbdb3bbb6 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
   --> tests/fail/intrinsics/copy_unaligned.rs:LL:CC
    |
-LL |         copy_nonoverlapping(&data[5], ptr, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
+LL |         std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.rs b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
new file mode 100644
index 00000000000..9f809039ada
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
@@ -0,0 +1,12 @@
+//@error-in-other-file: `read` from stdin not available when isolation is enabled
+//@normalize-stderr-test: "src/sys/.*\.rs" -> "$$FILE"
+//@normalize-stderr-test: "\nLL \| .*" -> ""
+//@normalize-stderr-test: "\n... .*" -> ""
+//@normalize-stderr-test: "\| +[|_^]+" -> "| ^"
+//@normalize-stderr-test: "\n *= note:.*" -> ""
+use std::io::{self, Read};
+
+fn main() {
+    let mut bytes = [0u8; 512];
+    io::stdin().read(&mut bytes).unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
index bb7e8cef5dc..1a4d7e96329 100644
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
@@ -1,13 +1,14 @@
 error: unsupported operation: `read` from stdin not available when isolation is enabled
-  --> tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
+  --> RUSTLIB/std/$FILE:LL:CC
    |
-LL |         libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled
+   | ^ `read` from stdin not available when isolation is enabled
    |
    = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
    = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
+note: inside `main`
+  --> tests/fail/shims/isolated_stdin.rs:LL:CC
+   |
+   | ^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/many-seeds/reentrant-lock.rs b/src/tools/miri/tests/many-seeds/reentrant-lock.rs
new file mode 100644
index 00000000000..8a363179a9c
--- /dev/null
+++ b/src/tools/miri/tests/many-seeds/reentrant-lock.rs
@@ -0,0 +1,19 @@
+#![feature(reentrant_lock)]
+//! This is a regression test for
+//! <https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/reentrant.20lock.20failure.20on.20musl>.
+
+use std::cell::Cell;
+use std::sync::ReentrantLock;
+use std::thread;
+
+static LOCK: ReentrantLock<Cell<i32>> = ReentrantLock::new(Cell::new(0));
+
+fn main() {
+    for _ in 0..20 {
+        thread::spawn(move || {
+            let val = LOCK.lock();
+            val.set(val.get() + 1);
+            drop(val);
+        });
+    }
+}
diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs
index 0205433ad9f..e695ff2d57b 100644
--- a/src/tools/miri/tests/panic/transmute_fat2.rs
+++ b/src/tools/miri/tests/panic/transmute_fat2.rs
@@ -5,6 +5,8 @@ fn main() {
     let bad = unsafe { std::mem::transmute::<u128, &[u8]>(42 << 64) };
     #[cfg(all(target_endian = "little", target_pointer_width = "32"))]
     let bad = unsafe { std::mem::transmute::<u64, &[u8]>(42) };
+    #[cfg(all(target_endian = "big", target_pointer_width = "32"))]
+    let bad = unsafe { std::mem::transmute::<u64, &[u8]>(42 << 32) };
     // This created a slice with length 0, so the following will fail the bounds check.
     bad[0];
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
index cffcf4a867f..06a8cc7f487 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
@@ -11,6 +11,10 @@ fn main() {
         assert!(libc::fcntl(1, libc::F_DUPFD, 0) >= 0);
     }
 
+    // Although `readlink` and `stat` require disable-isolation mode
+    // to properly run, they are tested with isolation mode on to check the error emitted
+    // with `-Zmiri-isolation-error=warn-nobacktrace`.
+
     // test `readlink`
     let mut buf = vec![0; "foo_link.txt".len() + 1];
     unsafe {
diff --git a/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs
new file mode 100644
index 00000000000..9a868128d27
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs
@@ -0,0 +1,51 @@
+//@only-target: freebsd
+//@compile-flags: -Zmiri-num-cpus=256
+
+use std::mem;
+
+fn getaffinity() {
+    let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
+    unsafe {
+        if libc::cpuset_getaffinity(
+            libc::CPU_LEVEL_WHICH,
+            libc::CPU_WHICH_PID,
+            -1,
+            size_of::<libc::cpuset_t>(),
+            &mut set,
+        ) == 0
+        {
+            assert!(libc::CPU_COUNT(&set) == 256);
+        }
+    }
+}
+
+fn get_small_cpu_mask() {
+    let mut set: libc::cpuset_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    // 256 CPUs so we need 32 bytes to represent this mask.
+    // According to Freebsd only when `cpusetsize` is smaller than this value, does it return with ERANGE
+
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 32, &mut set)
+    };
+    assert_eq!(err, 0, "Success Expected");
+
+    // 31 is not enough, so it should fail.
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 31, &mut set)
+    };
+    assert_eq!(err, -1, "Expected Failure");
+    assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
+
+    // Zero should fail as well.
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 0, &mut set)
+    };
+    assert_eq!(err, -1, "Expected Failure");
+    assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
+}
+
+fn main() {
+    getaffinity();
+    get_small_cpu_mask();
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
index 698ca4e0b4b..4ca19046b67 100644
--- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -2,25 +2,28 @@
 //@compile-flags: -Zmiri-disable-isolation
 #![allow(nonstandard_style)]
 
-use std::io::ErrorKind;
+use std::io::{ErrorKind, Read, Write};
 use std::os::windows::ffi::OsStrExt;
+use std::os::windows::io::AsRawHandle;
 use std::path::Path;
-use std::ptr;
+use std::{fs, ptr};
 
 #[path = "../../utils/mod.rs"]
 mod utils;
 
+use windows_sys::Wdk::Storage::FileSystem::{NtReadFile, NtWriteFile};
 use windows_sys::Win32::Foundation::{
     CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ,
     GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED,
-    STATUS_IO_DEVICE_ERROR,
+    STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError,
 };
 use windows_sys::Win32::Storage::FileSystem::{
     BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW,
-    FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS,
-    FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
-    GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING,
+    FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT,
+    FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ,
+    FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx,
 };
+use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
 
 fn main() {
     unsafe {
@@ -31,6 +34,8 @@ fn main() {
         test_open_dir_reparse();
         test_delete_file();
         test_ntstatus_to_dos();
+        test_file_read_write();
+        test_file_seek();
     }
 }
 
@@ -199,13 +204,13 @@ unsafe fn test_open_dir_reparse() {
 unsafe fn test_delete_file() {
     let temp = utils::tmp().join("test_delete_file.txt");
     let raw_path = to_wide_cstr(&temp);
-    let _ = std::fs::File::create(&temp).unwrap();
+    let _ = fs::File::create(&temp).unwrap();
 
     if DeleteFileW(raw_path.as_ptr()) == 0 {
         panic!("Failed to delete file");
     }
 
-    match std::fs::File::open(temp) {
+    match fs::File::open(temp) {
         Ok(_) => panic!("File not deleted"),
         Err(e) => assert!(e.kind() == ErrorKind::NotFound, "File not deleted"),
     }
@@ -217,6 +222,82 @@ unsafe fn test_ntstatus_to_dos() {
     assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED);
 }
 
+unsafe fn test_file_read_write() {
+    let temp = utils::tmp().join("test_file_read_write.txt");
+    let file = fs::File::create(&temp).unwrap();
+    let handle = file.as_raw_handle();
+
+    // Testing NtWriteFile doesn't clobber the error
+    SetLastError(1234);
+
+    let text = b"Example text!";
+    let mut status = std::mem::zeroed::<IO_STATUS_BLOCK>();
+    let out = NtWriteFile(
+        handle,
+        ptr::null_mut(),
+        None,
+        ptr::null_mut(),
+        &mut status,
+        text.as_ptr().cast(),
+        text.len() as u32,
+        ptr::null_mut(),
+        ptr::null_mut(),
+    );
+
+    assert_eq!(out, status.Anonymous.Status);
+    assert_eq!(out, STATUS_SUCCESS);
+    assert_eq!(GetLastError(), 1234);
+
+    let file = fs::File::open(&temp).unwrap();
+    let handle = file.as_raw_handle();
+
+    // Testing NtReadFile doesn't clobber the error
+    SetLastError(1234);
+
+    let mut buffer = vec![0; 13];
+    let out = NtReadFile(
+        handle,
+        ptr::null_mut(),
+        None,
+        ptr::null_mut(),
+        &mut status,
+        buffer.as_mut_ptr().cast(),
+        buffer.len() as u32,
+        ptr::null_mut(),
+        ptr::null_mut(),
+    );
+
+    assert_eq!(out, status.Anonymous.Status);
+    assert_eq!(out, STATUS_SUCCESS);
+    assert_eq!(buffer, text);
+    assert_eq!(GetLastError(), 1234);
+}
+
+unsafe fn test_file_seek() {
+    let temp = utils::tmp().join("test_file_seek.txt");
+    let mut file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap();
+    file.write_all(b"Hello, World!\n").unwrap();
+
+    let handle = file.as_raw_handle();
+
+    if SetFilePointerEx(handle, 7, ptr::null_mut(), FILE_BEGIN) == 0 {
+        panic!("Failed to seek");
+    }
+
+    let mut buf = vec![0; 5];
+    file.read(&mut buf).unwrap();
+    assert_eq!(buf, b"World");
+
+    let mut pos = 0;
+    if SetFilePointerEx(handle, -7, &mut pos, FILE_CURRENT) == 0 {
+        panic!("Failed to seek");
+    }
+    buf.truncate(2);
+    file.read_exact(&mut buf).unwrap();
+    assert_eq!(buf, b", ");
+    assert_eq!(pos, 5);
+}
+
 fn to_wide_cstr(path: &Path) -> Vec<u16> {
     let mut raw_path = path.as_os_str().encode_wide().collect::<Vec<_>>();
     raw_path.extend([0, 0]);
diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs
index 2b2e89e6d70..3de34e570c7 100644
--- a/src/tools/miri/tests/pass/atomic.rs
+++ b/src/tools/miri/tests/pass/atomic.rs
@@ -7,15 +7,17 @@
 #![allow(static_mut_refs)]
 
 use std::sync::atomic::Ordering::*;
-use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, compiler_fence, fence};
+use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, compiler_fence, fence};
 
 fn main() {
     atomic_bool();
     atomic_all_ops();
-    atomic_u64();
     atomic_fences();
     atomic_ptr();
     weak_sometimes_fails();
+
+    #[cfg(target_has_atomic = "64")]
+    atomic_u64();
 }
 
 fn atomic_bool() {
@@ -36,25 +38,10 @@ fn atomic_bool() {
     }
 }
 
-// There isn't a trait to use to make this generic, so just use a macro
-macro_rules! compare_exchange_weak_loop {
-    ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => {
-        loop {
-            match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) {
-                Ok(n) => {
-                    assert_eq!(n, $from);
-                    break;
-                }
-                Err(n) => assert_eq!(n, $from),
-            }
-        }
-    };
-}
-
 /// Make sure we can handle all the intrinsics
 fn atomic_all_ops() {
     static ATOMIC: AtomicIsize = AtomicIsize::new(0);
-    static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0);
+    static ATOMIC_UNSIGNED: AtomicUsize = AtomicUsize::new(0);
 
     let load_orders = [Relaxed, Acquire, SeqCst];
     let stored_orders = [Relaxed, Release, SeqCst];
@@ -94,9 +81,26 @@ fn atomic_all_ops() {
     }
 }
 
+#[cfg(target_has_atomic = "64")]
 fn atomic_u64() {
+    use std::sync::atomic::AtomicU64;
     static ATOMIC: AtomicU64 = AtomicU64::new(0);
 
+    // There isn't a trait to use to make this generic, so just use a macro
+    macro_rules! compare_exchange_weak_loop {
+        ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => {
+            loop {
+                match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) {
+                    Ok(n) => {
+                        assert_eq!(n, $from);
+                        break;
+                    }
+                    Err(n) => assert_eq!(n, $from),
+                }
+            }
+        };
+    }
+
     ATOMIC.store(1, SeqCst);
     assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1));
     assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1));
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index d0a7f245ee0..315637ff7ec 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -17,20 +17,20 @@ mod utils;
 
 fn main() {
     test_path_conversion();
+    test_file();
     test_file_create_new();
+    test_metadata();
+    test_seek();
+    test_errors();
+    test_from_raw_os_error();
     // Windows file handling is very incomplete.
     if cfg!(not(windows)) {
-        test_file();
-        test_seek();
         test_file_clone();
-        test_metadata();
         test_file_set_len();
         test_file_sync();
-        test_errors();
         test_rename();
         test_directory();
         test_canonicalize();
-        test_from_raw_os_error();
         #[cfg(unix)]
         test_pread_pwrite();
     }
diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs
index 420ef95a0cb..a96b98c0227 100644
--- a/src/tools/miri/tests/pass/shims/io.rs
+++ b/src/tools/miri/tests/pass/shims/io.rs
@@ -1,8 +1,10 @@
-use std::io::{self, IsTerminal};
+use std::io::{self, IsTerminal, Write};
 
 fn main() {
-    // We can't really assume that this is truly a terminal, and anyway on Windows Miri will always
-    // return `false` here, but we can check that the call succeeds.
+    io::stdout().write_all(b"stdout\n").unwrap();
+    io::stderr().write_all(b"stderr\n").unwrap();
+
+    // We can't assume that this is truly a terminal, but we can check that the call succeeds.
     io::stdout().is_terminal();
 
     // Ensure we can format `io::Error` created from OS errors
diff --git a/src/tools/miri/tests/pass/shims/io.stderr b/src/tools/miri/tests/pass/shims/io.stderr
new file mode 100644
index 00000000000..af6415db3c7
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stderr
@@ -0,0 +1 @@
+stderr
diff --git a/src/tools/miri/tests/pass/shims/io.stdout b/src/tools/miri/tests/pass/shims/io.stdout
new file mode 100644
index 00000000000..faa3a15c184
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stdout
@@ -0,0 +1 @@
+stdout
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index 0f1fda38115..a06e59fcc41 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -80,7 +80,7 @@ pub fn bolt_optimize(
         // Move jump tables to a separate section
         .arg("-jump-tables=move")
         // Fold functions with identical code
-        .arg("-icf=1")
+        .arg("-icf=all")
         // The following flag saves about 50 MiB of libLLVM.so size.
         // However, it succeeds very non-deterministically. To avoid frequent artifact size swings,
         // it is kept disabled for now.
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000..466672e3d48
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,4 @@
+contact_links:
+  - name: Questions regarding rust-analyzer
+    url: https://github.com/rust-lang/rust-analyzer/discussions
+    about: Please ask and answer questions here instead of opening an issue
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
index 23c43443c84..2b44bdc748f 100644
--- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
+++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
@@ -12,5 +12,3 @@ Troubleshooting guide: https://rust-analyzer.github.io/book/troubleshooting.html
 
 Please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
 -->
-
-This is a serious regression in nightly and it's important to fix it before the next release.
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md
deleted file mode 100644
index a90ade882bd..00000000000
--- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: Support Question
-about: A question regarding functionality of rust-analyzer.
-title: ''
-labels: 'C-support'
-assignees: ''
-
----
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index a4146d60218..dc2f432bbc7 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -18,9 +18,9 @@ jobs:
     steps:
       - name: Install Rust toolchain
         run: |
-          rustup update --no-self-update stable
-          rustup default stable
-          rustup component add --toolchain stable rust-src
+          rustup update --no-self-update beta
+          rustup default beta
+          rustup component add --toolchain beta rust-src
 
       - name: Checkout repository
         uses: actions/checkout@v4
@@ -61,9 +61,9 @@ jobs:
     steps:
       - name: Install Rust toolchain
         run: |
-          rustup update --no-self-update stable
-          rustup default stable
-          rustup component add --toolchain stable rust-src
+          rustup update --no-self-update beta
+          rustup default beta
+          rustup component add --toolchain beta rust-src
 
       - name: Checkout repository
         uses: actions/checkout@v4
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8d6c8284e44..bd8146defae 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -61,9 +61,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
-version = "0.3.74"
+version = "0.3.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
 dependencies = [
  "addr2line",
  "cfg-if",
@@ -80,6 +80,7 @@ version = "0.0.0"
 dependencies = [
  "cfg",
  "dashmap",
+ "indexmap",
  "intern",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "query-group-macro",
@@ -316,9 +317,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
 [[package]]
 name = "ctrlc"
-version = "3.4.5"
+version = "3.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
+checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
 dependencies = [
  "nix",
  "windows-sys 0.59.0",
@@ -472,9 +473,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
 
 [[package]]
 name = "flate2"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -1010,9 +1011,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
  "hashbrown 0.15.2",
@@ -1123,12 +1124,12 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "libloading"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.53.0",
 ]
 
 [[package]]
@@ -1358,9 +1359,9 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.29.0"
+version = "0.30.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
 dependencies = [
  "bitflags 2.9.0",
  "cfg-if",
@@ -1640,14 +1641,14 @@ dependencies = [
 
 [[package]]
 name = "process-wrap"
-version = "8.2.0"
+version = "8.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54"
+checksum = "a3ef4f2f0422f23a82ec9f628ea2acd12871c81a9362b02c43c1aa86acfc3ba1"
 dependencies = [
  "indexmap",
  "nix",
  "tracing",
- "windows 0.59.0",
+ "windows 0.61.1",
 ]
 
 [[package]]
@@ -1749,9 +1750,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912228bd8ed3beff1f6f9e5e2d4b37c0827ba3e2070060bf3858a311d0e29e30"
+checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230"
 dependencies = [
  "bitflags 2.9.0",
  "ra-ap-rustc_hashes",
@@ -1761,18 +1762,18 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_hashes"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba520764daf057a9d963fa769f4762eaf87ac5d4900ae76195eeead64cd35afd"
+checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d"
 dependencies = [
  "rustc-stable-hash",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b76b5f9ee55f2d0e5a65bea23f6d738893349ce8d3d17a6720933e647ab04978"
+checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1780,9 +1781,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddd972eb1face2fcaa0d94c01d97862fb955b5561d4f5932003bce8a6cadd8c6"
+checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1791,9 +1792,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a9876456fb2521097deef33ddeac1c18260c8eafb68054d986f8b9d6ce9fa"
+checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1802,9 +1803,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e85de58dfcc60a5f9d5ec0157a657e3f84abd8f22c8a0c4d707cfb42c9011f4"
+checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8"
 dependencies = [
  "ra-ap-rustc_lexer",
  "rustc-literal-escaper",
@@ -1812,9 +1813,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.110.0"
+version = "0.113.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceadf9db550db67deff7eff2e2765109b860c9d7e5bdfca144863020289c823d"
+checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.1.1",
@@ -2228,6 +2229,7 @@ version = "0.0.0"
 dependencies = [
  "backtrace",
  "crossbeam-channel",
+ "crossbeam-utils",
  "itertools 0.14.0",
  "jod-thread",
  "libc",
@@ -2750,12 +2752,24 @@ dependencies = [
 
 [[package]]
 name = "windows"
-version = "0.59.0"
+version = "0.61.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
+checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
 dependencies = [
- "windows-core 0.59.0",
- "windows-targets 0.53.0",
+ "windows-collections",
+ "windows-core 0.61.0",
+ "windows-future",
+ "windows-link",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
+dependencies = [
+ "windows-core 0.61.0",
 ]
 
 [[package]]
@@ -2773,15 +2787,25 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.59.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-implement 0.59.0",
- "windows-interface 0.59.0",
- "windows-result 0.3.1",
- "windows-strings 0.3.1",
- "windows-targets 0.53.0",
+ "windows-implement 0.60.0",
+ "windows-interface 0.59.1",
+ "windows-link",
+ "windows-result 0.3.2",
+ "windows-strings 0.4.0",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
+dependencies = [
+ "windows-core 0.61.0",
+ "windows-link",
 ]
 
 [[package]]
@@ -2797,9 +2821,9 @@ dependencies = [
 
 [[package]]
 name = "windows-implement"
-version = "0.59.0"
+version = "0.60.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2819,9 +2843,9 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.59.0"
+version = "0.59.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2830,9 +2854,19 @@ dependencies = [
 
 [[package]]
 name = "windows-link"
-version = "0.1.0"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[package]]
+name = "windows-numerics"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
+dependencies = [
+ "windows-core 0.61.0",
+ "windows-link",
+]
 
 [[package]]
 name = "windows-result"
@@ -2845,9 +2879,9 @@ dependencies = [
 
 [[package]]
 name = "windows-result"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
 dependencies = [
  "windows-link",
 ]
@@ -2864,9 +2898,9 @@ dependencies = [
 
 [[package]]
 name = "windows-strings"
-version = "0.3.1"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
 dependencies = [
  "windows-link",
 ]
@@ -3230,17 +3264,14 @@ dependencies = [
 
 [[package]]
 name = "zip"
-version = "2.4.2"
+version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
+checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
 dependencies = [
  "arbitrary",
  "crc32fast",
- "crossbeam-utils",
- "displaydoc",
  "flate2",
  "indexmap",
  "memchr",
- "thiserror 2.0.12",
  "time",
 ]
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index c4c2fdf34ba..07731bae3f3 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -85,11 +85,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 edition = { path = "./crates/edition", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.110", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.110", default-features = false }
-ra-ap-rustc_index = { version = "0.110", default-features = false }
-ra-ap-rustc_abi = { version = "0.110", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.110", default-features = false }
+ra-ap-rustc_lexer = { version = "0.113", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.113", default-features = false }
+ra-ap-rustc_index = { version = "0.113", default-features = false }
+ra-ap-rustc_abi = { version = "0.113", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
@@ -132,7 +132,10 @@ pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.6", default-features = false }
 rayon = "1.10.0"
 rowan = "=0.15.15"
-salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] }
+salsa = { version = "0.21.1", default-features = false, features = [
+  "rayon",
+  "salsa_unstable",
+] }
 salsa-macros = "0.21.1"
 semver = "1.0.26"
 serde = { version = "1.0.219" }
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index e2e3253773f..3b423a86f97 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -21,6 +21,7 @@ rustc-hash.workspace = true
 triomphe.workspace = true
 semver.workspace = true
 tracing.workspace = true
+indexmap.workspace = true
 
 # local deps
 cfg.workspace = true
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 9660e6e87cc..d42d7e5707d 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -14,7 +14,7 @@ use dashmap::DashMap;
 use dashmap::mapref::entry::Entry;
 use intern::Symbol;
 use la_arena::{Arena, Idx, RawIdx};
-use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
+use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
 use salsa::{Durability, Setter};
 use span::Edition;
 use triomphe::Arc;
@@ -24,6 +24,8 @@ use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb};
 
 pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
 
+type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>;
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct SourceRootId(pub u32);
 
@@ -474,7 +476,9 @@ impl CrateGraphBuilder {
     }
 
     pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
-        let mut all_crates = Vec::with_capacity(self.arena.len());
+        // For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
+        // We use an `IndexSet` because the list needs to be topologically sorted.
+        let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
         let mut visited = FxHashMap::default();
         let mut visited_root_files = FxHashSet::default();
 
@@ -494,9 +498,11 @@ impl CrateGraphBuilder {
             );
         }
 
-        if **old_all_crates != *all_crates {
+        if old_all_crates.len() != all_crates.len()
+            || old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
+        {
             db.set_all_crates_with_durability(
-                Arc::new(all_crates.into_boxed_slice()),
+                Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
                 Durability::MEDIUM,
             );
         }
@@ -509,7 +515,7 @@ impl CrateGraphBuilder {
             crates_map: &CratesMap,
             visited: &mut FxHashMap<CrateBuilderId, Crate>,
             visited_root_files: &mut FxHashSet<FileId>,
-            all_crates: &mut Vec<Crate>,
+            all_crates: &mut FxIndexSet<Crate>,
             source: CrateBuilderId,
         ) -> Crate {
             if let Some(&crate_id) = visited.get(&source) {
@@ -597,7 +603,7 @@ impl CrateGraphBuilder {
                     input
                 }
             };
-            all_crates.push(crate_input);
+            all_crates.insert(crate_input);
             visited.insert(source, crate_input);
             crate_input
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 2cbdbe16f9b..4a9a3b12cfa 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -24,8 +24,8 @@ use crate::{
     item_tree::{AttrOwner, ItemTree},
     lang_item::{self, LangItem},
     nameres::{
-        DefMap, LocalDefMap,
         assoc::{ImplItems, TraitItems},
+        crate_def_map,
         diagnostics::DefDiagnostics,
     },
     signatures::{
@@ -111,16 +111,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
     #[salsa::invoke(ItemTree::block_item_tree_query)]
     fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
 
-    #[salsa::invoke(DefMap::crate_local_def_map_query)]
-    fn crate_local_def_map(&self, krate: Crate) -> (Arc<DefMap>, Arc<LocalDefMap>);
-
-    #[salsa::invoke(DefMap::crate_def_map_query)]
-    fn crate_def_map(&self, krate: Crate) -> Arc<DefMap>;
-
-    /// Computes the block-level `DefMap`.
-    #[salsa::invoke(DefMap::block_def_map_query)]
-    fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
-
     /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
     #[salsa::invoke(macro_def)]
     fn macro_def(&self, m: MacroId) -> MacroDefId;
@@ -363,7 +353,7 @@ fn include_macro_invoc(
     db: &dyn DefDatabase,
     krate: Crate,
 ) -> Arc<[(MacroCallId, EditionedFileId)]> {
-    db.crate_def_map(krate)
+    crate_def_map(db, krate)
         .modules
         .values()
         .flat_map(|m| m.scope.iter_macro_invoc())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index e3775c4931a..f617c3225ae 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -19,7 +19,6 @@ use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::{Edition, SyntaxContext};
 use syntax::{AstPtr, SyntaxNodePtr, ast};
-use triomphe::Arc;
 use tt::TextRange;
 
 use crate::{
@@ -30,7 +29,7 @@ use crate::{
         Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
         PatId, RecordFieldPat, Statement,
     },
-    nameres::DefMap,
+    nameres::{DefMap, block_def_map},
     type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
 };
 
@@ -225,8 +224,8 @@ impl ExpressionStore {
     pub fn blocks<'a>(
         &'a self,
         db: &'a dyn DefDatabase,
-    ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
-        self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
+    ) -> impl Iterator<Item = (BlockId, &'a DefMap)> + 'a {
+        self.block_scopes.iter().map(move |&block| (block, block_def_map(db, block)))
     }
 
     pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -299,17 +298,16 @@ impl ExpressionStore {
             Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
                 AsmOperand::In { expr, .. }
                 | AsmOperand::Out { expr: Some(expr), .. }
-                | AsmOperand::InOut { expr, .. } => f(*expr),
+                | AsmOperand::InOut { expr, .. }
+                | AsmOperand::Const(expr)
+                | AsmOperand::Label(expr) => f(*expr),
                 AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
                     f(*in_expr);
                     if let Some(out_expr) = out_expr {
                         f(*out_expr);
                     }
                 }
-                AsmOperand::Out { expr: None, .. }
-                | AsmOperand::Const(_)
-                | AsmOperand::Label(_)
-                | AsmOperand::Sym(_) => (),
+                AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
             }),
             Expr::If { condition, then_branch, else_branch } => {
                 f(*condition);
@@ -436,17 +434,16 @@ impl ExpressionStore {
             Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
                 AsmOperand::In { expr, .. }
                 | AsmOperand::Out { expr: Some(expr), .. }
-                | AsmOperand::InOut { expr, .. } => f(*expr),
+                | AsmOperand::InOut { expr, .. }
+                | AsmOperand::Const(expr)
+                | AsmOperand::Label(expr) => f(*expr),
                 AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
                     f(*in_expr);
                     if let Some(out_expr) = out_expr {
                         f(*out_expr);
                     }
                 }
-                AsmOperand::Out { expr: None, .. }
-                | AsmOperand::Const(_)
-                | AsmOperand::Label(_)
-                | AsmOperand::Sym(_) => (),
+                AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
             }),
             Expr::If { condition, then_branch, else_branch } => {
                 f(*condition);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 50505d54ba2..29871f5e04d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -56,7 +56,7 @@ use crate::{
     item_scope::BuiltinShadowMode,
     item_tree::FieldsShape,
     lang_item::LangItem,
-    nameres::{DefMap, LocalDefMap, MacroSubNs},
+    nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},
     type_ref::{
         ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,
         RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,
@@ -436,8 +436,8 @@ pub struct ExprCollector<'db> {
     db: &'db dyn DefDatabase,
     cfg_options: &'db CfgOptions,
     expander: Expander,
-    def_map: Arc<DefMap>,
-    local_def_map: Arc<LocalDefMap>,
+    def_map: &'db DefMap,
+    local_def_map: &'db LocalDefMap,
     module: ModuleId,
     pub store: ExpressionStoreBuilder,
     pub(crate) source_map: ExpressionStoreSourceMap,
@@ -544,7 +544,7 @@ impl ExprCollector<'_> {
         current_file_id: HirFileId,
     ) -> ExprCollector<'_> {
         let (def_map, local_def_map) = module.local_def_map(db);
-        let expander = Expander::new(db, current_file_id, &def_map);
+        let expander = Expander::new(db, current_file_id, def_map);
         ExprCollector {
             db,
             cfg_options: module.krate().cfg_options(db),
@@ -1947,7 +1947,7 @@ impl ExprCollector<'_> {
                 let resolver = |path: &_| {
                     self.def_map
                         .resolve_path(
-                            &self.local_def_map,
+                            self.local_def_map,
                             self.db,
                             module,
                             path,
@@ -2163,12 +2163,12 @@ impl ExprCollector<'_> {
         };
 
         let (module, def_map) =
-            match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
+            match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
                 Some((def_map, block_id)) => {
                     self.store.block_scopes.push(block_id);
                     (def_map.module_id(DefMap::ROOT), def_map)
                 }
-                None => (self.module, self.def_map.clone()),
+                None => (self.module, self.def_map),
             };
         let prev_def_map = mem::replace(&mut self.def_map, def_map);
         let prev_local_module = mem::replace(&mut self.module, module);
@@ -2247,7 +2247,7 @@ impl ExprCollector<'_> {
                     // This could also be a single-segment path pattern. To
                     // decide that, we need to try resolving the name.
                     let (resolved, _) = self.def_map.resolve_path(
-                        &self.local_def_map,
+                        self.local_def_map,
                         self.db,
                         self.module.local_id,
                         &name.clone().into(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
index 629d1f2ada7..be006c98a58 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
@@ -232,6 +232,14 @@ pub(super) fn lower_path(
             .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..)));
     }
 
+    if let Some(last_segment_args @ Some(GenericArgs { has_self_type: true, .. })) =
+        generic_args.last_mut()
+    {
+        // Well-formed code cannot have `<T as Trait>` without an associated item after,
+        // and this causes panics in hir-ty lowering.
+        *last_segment_args = None;
+    }
+
     let mod_path = Interned::new(ModPath::from_segments(kind, segments));
     if type_anchor.is_none() && generic_args.is_empty() {
         return Some(Path::BarePath(mod_path));
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
index 337cb103bde..8fd81c7b3df 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
@@ -4,7 +4,6 @@ use syntax::ast::{self, make};
 use test_fixture::WithFixture;
 
 use crate::{
-    db::DefDatabase,
     expr_store::{
         ExpressionStore,
         lower::{
@@ -14,13 +13,15 @@ use crate::{
         path::Path,
         pretty,
     },
+    nameres::crate_def_map,
     test_db::TestDB,
 };
 
 fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
     let (db, file_id) = TestDB::with_single_file("");
     let krate = db.fetch_test_crate();
-    let mut ctx = ExprCollector::new(&db, db.crate_def_map(krate).root_module_id(), file_id.into());
+    let mut ctx =
+        ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
     let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator);
     let store = ctx.store.finish();
     (db, store, lowered_path)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 431ea9eb1d4..a46711c67e8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -324,11 +324,13 @@ mod tests {
     use test_fixture::WithFixture;
     use test_utils::{assert_eq_text, extract_offset};
 
-    use crate::{FunctionId, ModuleDefId, db::DefDatabase, test_db::TestDB};
+    use crate::{
+        FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB,
+    };
 
     fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
         let krate = db.test_crate();
-        let crate_def_map = db.crate_def_map(krate);
+        let crate_def_map = crate_def_map(db, krate);
 
         let module = crate_def_map.modules_for_file(db, file_id).next().unwrap();
         let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index d6645dc1d1d..29e249b07a7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -1,9 +1,10 @@
 mod block;
 
-use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, test_db::TestDB};
+use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, nameres::crate_def_map, test_db::TestDB};
 use expect_test::{Expect, expect};
 use la_arena::RawIdx;
 use test_fixture::WithFixture;
+use triomphe::Arc;
 
 use super::super::*;
 
@@ -11,7 +12,7 @@ fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>,
     let db = TestDB::with_files(ra_fixture);
 
     let krate = db.fetch_test_crate();
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
     let mut fn_def = None;
     'outer: for (_, module) in def_map.modules() {
         for decl in module.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index da3b65d4203..5f7b510bba4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,8 +189,8 @@ fn f() {
 }
     "#,
         expect![[r#"
-            BlockId(3801) in BlockRelativeModuleId { block: Some(BlockId(3800)), local_id: Idx::<ModuleData>(1) }
-            BlockId(3800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
+            BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
+            BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
             crate scope
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
index 80561d64708..efb558a7758 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
@@ -1,6 +1,7 @@
 use crate::{
     GenericDefId, ModuleDefId,
     expr_store::pretty::{print_function, print_struct},
+    nameres::crate_def_map,
     test_db::TestDB,
 };
 use expect_test::{Expect, expect};
@@ -12,7 +13,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe
     let db = TestDB::with_files(ra_fixture);
 
     let krate = db.fetch_test_crate();
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
     let mut defs = vec![];
     for (_, module) in def_map.modules() {
         for decl in module.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 9d62d9ce652..bb75621c7e0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -52,7 +52,7 @@ pub fn find_path(
             ignore_local_imports,
             is_std_item: item_module.krate().data(db).origin.is_lang(),
             from,
-            from_def_map: &from.def_map(db),
+            from_def_map: from.def_map(db),
             fuel: Cell::new(FIND_PATH_FUEL),
         },
         item,
@@ -691,7 +691,7 @@ mod tests {
         let (def_map, local_def_map) = module.local_def_map(&db);
         let resolved = def_map
             .resolve_path(
-                &local_def_map,
+                local_def_map,
                 &db,
                 module.local_id,
                 &mod_path,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
index f27a4062a63..271484da7b9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -297,7 +297,8 @@ pub(crate) fn parse(
                     unfinished_literal.clear();
                 }
 
-                let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
+                let span =
+                    parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
                 placeholder_index += 1;
 
                 let position_span = to_span(position_span);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index db571f045d7..a6138fb6821 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -16,7 +16,7 @@ use crate::{
     AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
     db::DefDatabase,
     item_scope::{ImportOrExternCrate, ItemInNs},
-    nameres::DefMap,
+    nameres::{DefMap, crate_def_map},
     visibility::Visibility,
 };
 
@@ -129,7 +129,7 @@ impl ImportMap {
     fn collect_import_map(db: &dyn DefDatabase, krate: Crate) -> ImportMapIndex {
         let _p = tracing::info_span!("collect_import_map").entered();
 
-        let def_map = db.crate_def_map(krate);
+        let def_map = crate_def_map(db, krate);
         let mut map = FxIndexMap::default();
 
         // We look only into modules that are public(ly reexported), starting with the crate root.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 51a833b5f15..59344641f47 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -10,6 +10,7 @@ use triomphe::Arc;
 use crate::{
     AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
     StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
+    nameres::crate_def_map,
 };
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -90,7 +91,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
 
     let mut lang_items = LangItems::default();
 
-    let crate_def_map = db.crate_def_map(krate);
+    let crate_def_map = crate_def_map(db, krate);
 
     for (_, module_data) in crate_def_map.modules() {
         for impl_def in module_data.scope.impls() {
@@ -209,7 +210,7 @@ pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option
 
     let mut traits = Vec::new();
 
-    let crate_def_map = db.crate_def_map(krate);
+    let crate_def_map = crate_def_map(db, krate);
 
     for (_, module_data) in crate_def_map.modules() {
         for def in module_data.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 28011bda7c5..b41ff026bca 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -92,7 +92,7 @@ use crate::{
         Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
         Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
     },
-    nameres::LocalDefMap,
+    nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
     signatures::VariantFields,
 };
 
@@ -324,12 +324,13 @@ pub struct CrateRootModuleId {
 }
 
 impl CrateRootModuleId {
-    pub fn def_map(&self, db: &dyn DefDatabase) -> Arc<DefMap> {
-        db.crate_def_map(self.krate)
+    pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
+        crate_def_map(db, self.krate)
     }
 
-    pub(crate) fn local_def_map(&self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
-        db.crate_local_def_map(self.krate)
+    pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
+        let def_map = crate_local_def_map(db, self.krate);
+        (def_map.def_map(db), def_map.local(db))
     }
 
     pub fn krate(self) -> Crate {
@@ -390,26 +391,29 @@ pub struct ModuleId {
 }
 
 impl ModuleId {
-    pub fn def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
+    pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
         match self.block {
-            Some(block) => db.block_def_map(block),
-            None => db.crate_def_map(self.krate),
+            Some(block) => block_def_map(db, block),
+            None => crate_def_map(db, self.krate),
         }
     }
 
-    pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
+    pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
         match self.block {
-            Some(block) => (db.block_def_map(block), self.only_local_def_map(db)),
-            None => db.crate_local_def_map(self.krate),
+            Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
+            None => {
+                let def_map = crate_local_def_map(db, self.krate);
+                (def_map.def_map(db), def_map.local(db))
+            }
         }
     }
 
-    pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> Arc<LocalDefMap> {
-        db.crate_local_def_map(self.krate).1
+    pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap {
+        crate_local_def_map(db, self.krate).local(db)
     }
 
-    pub fn crate_def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
-        db.crate_def_map(self.krate)
+    pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap {
+        crate_def_map(db, self.krate)
     }
 
     pub fn krate(self) -> Crate {
@@ -701,6 +705,16 @@ pub enum AssocItemId {
 // casting them, and somehow making the constructors private, which would be annoying.
 impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
 
+impl From<AssocItemId> for ModuleDefId {
+    fn from(item: AssocItemId) -> Self {
+        match item {
+            AssocItemId::FunctionId(f) => f.into(),
+            AssocItemId::ConstId(c) => c.into(),
+            AssocItemId::TypeAliasId(t) => t.into(),
+        }
+    }
+}
+
 #[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
 pub enum GenericDefId {
     AdtId(AdtId),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index e21d1415aa2..3027aff3163 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -454,13 +454,13 @@ fn test_concat_expand() {
 #[rustc_builtin_macro]
 macro_rules! concat {}
 
-fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', '\0'); }
+fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', -4, - 4, '\0'); }
 "##,
         expect![[r##"
 #[rustc_builtin_macro]
 macro_rules! concat {}
 
-fn main() { "foo0\"bar\"\nfalse\"\u{0}"; }
+fn main() { "foo0\"bar\"\nfalse\"-4-4\u{0}"; }
 "##]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 800c96ebdae..dc4334ee081 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -39,7 +39,7 @@ use test_fixture::WithFixture;
 use crate::{
     AdtId, Lookup, ModuleDefId,
     db::DefDatabase,
-    nameres::{DefMap, ModuleSource},
+    nameres::{DefMap, ModuleSource, crate_def_map},
     src::HasSource,
     test_db::TestDB,
     tt::TopSubtree,
@@ -49,7 +49,7 @@ use crate::{
 fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
     let errors = def_map
         .modules()
         .flat_map(|module| module.1.scope.all_macro_calls())
@@ -113,7 +113,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
 
                 let (body, sm) = db.body_with_source_map(body);
                 if let Some(it) =
-                    body.blocks(db).find_map(|block| resolve(db, &block.1, ast_id, ast_ptr))
+                    body.blocks(db).find_map(|block| resolve(db, block.1, ast_id, ast_ptr))
                 {
                     return Some(it);
                 }
@@ -127,7 +127,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
 
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
     let krate = db.fetch_test_crate();
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
     let local_id = DefMap::ROOT;
     let source = def_map[local_id].definition_source(&db);
     let source_file = match source.value {
@@ -142,7 +142,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         let ast_id = db.ast_id_map(source.file_id).ast_id(&macro_call_node);
         let ast_id = InFile::new(source.file_id, ast_id);
         let ptr = InFile::new(source.file_id, AstPtr::new(&macro_call_node));
-        let macro_call_id = resolve(&db, &def_map, ast_id, ptr)
+        let macro_call_id = resolve(&db, def_map, ast_id, ptr)
             .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}"));
         let expansion_result = db.parse_macro_expansion(macro_call_id);
         expansions.push((macro_call_node.clone(), expansion_result));
@@ -380,8 +380,4 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
             panic!("got invalid macro input: {:?}", parse.errors());
         }
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index fc66d8e28d8..d4b30a1d3e6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -112,6 +112,18 @@ pub struct LocalDefMap {
     extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
 }
 
+impl std::hash::Hash for LocalDefMap {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        let LocalDefMap { extern_prelude } = self;
+        extern_prelude.len().hash(state);
+        for (name, (crate_root, extern_crate)) in extern_prelude {
+            name.hash(state);
+            crate_root.hash(state);
+            extern_crate.hash(state);
+        }
+    }
+}
+
 impl LocalDefMap {
     pub(crate) const EMPTY: &Self =
         &Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
@@ -250,7 +262,7 @@ struct BlockRelativeModuleId {
 }
 
 impl BlockRelativeModuleId {
-    fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> {
+    fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
         self.into_module(krate).def_map(db)
     }
 
@@ -358,6 +370,87 @@ pub struct ModuleData {
     pub scope: ItemScope,
 }
 
+#[inline]
+pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
+    crate_local_def_map(db, crate_id).def_map(db)
+}
+
+#[allow(unused_lifetimes)]
+mod __ {
+    use super::*;
+    #[salsa_macros::tracked]
+    pub(crate) struct DefMapPair<'db> {
+        #[tracked]
+        #[return_ref]
+        pub(crate) def_map: DefMap,
+        #[return_ref]
+        pub(crate) local: LocalDefMap,
+    }
+}
+pub(crate) use __::DefMapPair;
+
+#[salsa_macros::tracked(return_ref)]
+pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
+    let krate = crate_id.data(db);
+    let _p = tracing::info_span!(
+        "crate_def_map_query",
+        name=?crate_id
+            .extra_data(db)
+            .display_name
+            .as_ref()
+            .map(|it| it.crate_name().to_smolstr())
+            .unwrap_or_default()
+    )
+    .entered();
+
+    let module_data = ModuleData::new(
+        ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
+        Visibility::Public,
+    );
+
+    let def_map =
+        DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
+    let (def_map, local_def_map) = collector::collect_defs(
+        db,
+        def_map,
+        TreeId::new(krate.root_file_id(db).into(), None),
+        None,
+    );
+
+    DefMapPair::new(db, def_map, local_def_map)
+}
+
+#[salsa_macros::tracked(return_ref)]
+pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
+    let BlockLoc { ast_id, module } = block_id.lookup(db);
+
+    let visibility = Visibility::Module(
+        ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
+        VisibilityExplicitness::Implicit,
+    );
+    let module_data =
+        ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
+
+    let local_def_map = crate_local_def_map(db, module.krate);
+    let def_map = DefMap::empty(
+        module.krate,
+        local_def_map.def_map(db).data.clone(),
+        module_data,
+        Some(BlockInfo {
+            block: block_id,
+            parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
+        }),
+    );
+
+    let (def_map, _) = collector::collect_defs(
+        db,
+        def_map,
+        TreeId::new(ast_id.file_id, Some(block_id)),
+        Some(local_def_map.local(db)),
+    );
+    def_map
+}
+
 impl DefMap {
     /// The module id of a crate or block root.
     pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
@@ -366,77 +459,6 @@ impl DefMap {
         self.data.edition
     }
 
-    pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> {
-        db.crate_local_def_map(crate_id).0
-    }
-
-    pub(crate) fn crate_local_def_map_query(
-        db: &dyn DefDatabase,
-        crate_id: Crate,
-    ) -> (Arc<DefMap>, Arc<LocalDefMap>) {
-        let krate = crate_id.data(db);
-        let _p = tracing::info_span!(
-            "crate_def_map_query",
-            name=?crate_id
-                .extra_data(db)
-                .display_name
-                .as_ref()
-                .map(|it| it.crate_name().to_smolstr())
-                .unwrap_or_default()
-        )
-        .entered();
-
-        let module_data = ModuleData::new(
-            ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
-            Visibility::Public,
-        );
-
-        let def_map = DefMap::empty(
-            crate_id,
-            Arc::new(DefMapCrateData::new(krate.edition)),
-            module_data,
-            None,
-        );
-        let (def_map, local_def_map) = collector::collect_defs(
-            db,
-            def_map,
-            TreeId::new(krate.root_file_id(db).into(), None),
-            None,
-        );
-
-        (Arc::new(def_map), Arc::new(local_def_map))
-    }
-
-    pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
-        let BlockLoc { ast_id, module } = block_id.lookup(db);
-
-        let visibility = Visibility::Module(
-            ModuleId { krate: module.krate, local_id: Self::ROOT, block: module.block },
-            VisibilityExplicitness::Implicit,
-        );
-        let module_data =
-            ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
-
-        let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate);
-        let def_map = DefMap::empty(
-            module.krate,
-            crate_map.data.clone(),
-            module_data,
-            Some(BlockInfo {
-                block: block_id,
-                parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
-            }),
-        );
-
-        let (def_map, _) = collector::collect_defs(
-            db,
-            def_map,
-            TreeId::new(ast_id.file_id, Some(block_id)),
-            Some(crate_local_map),
-        );
-        Arc::new(def_map)
-    }
-
     fn empty(
         krate: Crate,
         crate_data: Arc<DefMapCrateData>,
@@ -595,7 +617,7 @@ impl DefMap {
             go(&mut buf, db, current_map, "block scope", Self::ROOT);
             buf.push('\n');
             arc = block.parent.def_map(db, self.krate);
-            current_map = &arc;
+            current_map = arc;
         }
         go(&mut buf, db, current_map, "crate", Self::ROOT);
         return buf;
@@ -628,7 +650,7 @@ impl DefMap {
         while let Some(block) = current_map.block {
             format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
             arc = block.parent.def_map(db, self.krate);
-            current_map = &arc;
+            current_map = arc;
         }
 
         format_to!(buf, "crate scope\n");
@@ -708,7 +730,7 @@ impl DefMap {
         let mut block = self.block;
         while let Some(block_info) = block {
             let parent = block_info.parent.def_map(db, self.krate);
-            if let Some(it) = f(&parent, block_info.parent.local_id) {
+            if let Some(it) = f(parent, block_info.parent.local_id) {
                 return Some(it);
             }
             block = parent.block;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
index 448b908936a..d45709b8b90 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
@@ -66,6 +66,15 @@ impl TraitItems {
         })
     }
 
+    pub fn assoc_item_by_name(&self, name: &Name) -> Option<AssocItemId> {
+        self.items.iter().find_map(|&(ref item_name, item)| match item {
+            AssocItemId::FunctionId(_) if item_name == name => Some(item),
+            AssocItemId::TypeAliasId(_) if item_name == name => Some(item),
+            AssocItemId::ConstId(_) if item_name == name => Some(item),
+            _ => None,
+        })
+    }
+
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
         self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
@@ -108,8 +117,8 @@ impl ImplItems {
 struct AssocItemCollector<'a> {
     db: &'a dyn DefDatabase,
     module_id: ModuleId,
-    def_map: Arc<DefMap>,
-    local_def_map: Arc<LocalDefMap>,
+    def_map: &'a DefMap,
+    local_def_map: &'a LocalDefMap,
     diagnostics: Vec<DefDiagnostic>,
     container: ItemContainerId,
 
@@ -174,7 +183,7 @@ impl<'a> AssocItemCollector<'a> {
             let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
 
             match self.def_map.resolve_attr_macro(
-                &self.local_def_map,
+                self.local_def_map,
                 self.db,
                 self.module_id.local_id,
                 ast_id_with_path,
@@ -246,7 +255,7 @@ impl<'a> AssocItemCollector<'a> {
                 let resolver = |path: &_| {
                     self.def_map
                         .resolve_path(
-                            &self.local_def_map,
+                            self.local_def_map,
                             self.db,
                             self.module_id.local_id,
                             path,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 8df0f092cd0..350c97c3982 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -26,7 +26,7 @@ use syntax::ast;
 use triomphe::Arc;
 
 use crate::{
-    AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
+    AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
     ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
     LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
     MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
@@ -43,9 +43,10 @@ use crate::{
     nameres::{
         BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
         attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
+        crate_def_map,
         diagnostics::DefDiagnostic,
         mod_resolution::ModDir,
-        path_resolution::ReachedFixedPoint,
+        path_resolution::{ReachedFixedPoint, ResolvePathResult},
         proc_macro::{ProcMacroDef, ProcMacroKind, parse_macro_name_and_helper_attrs},
         sub_namespace_match,
     },
@@ -61,7 +62,7 @@ pub(super) fn collect_defs(
     db: &dyn DefDatabase,
     def_map: DefMap,
     tree_id: TreeId,
-    crate_local_def_map: Option<Arc<LocalDefMap>>,
+    crate_local_def_map: Option<&LocalDefMap>,
 ) -> (DefMap, LocalDefMap) {
     let krate = &def_map.krate.data(db);
     let cfg_options = def_map.krate.cfg_options(db);
@@ -216,7 +217,7 @@ struct DefCollector<'a> {
     def_map: DefMap,
     local_def_map: LocalDefMap,
     /// Set only in case of blocks.
-    crate_local_def_map: Option<Arc<LocalDefMap>>,
+    crate_local_def_map: Option<&'a LocalDefMap>,
     // The dependencies of the current crate, including optional deps like `test`.
     deps: FxHashMap<Name, BuiltDependency>,
     glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
@@ -533,7 +534,7 @@ impl DefCollector<'_> {
         );
 
         let (per_ns, _) = self.def_map.resolve_path(
-            self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+            self.crate_local_def_map.unwrap_or(&self.local_def_map),
             self.db,
             DefMap::ROOT,
             &path,
@@ -556,7 +557,7 @@ impl DefCollector<'_> {
     }
 
     fn local_def_map(&mut self) -> &LocalDefMap {
-        self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map)
+        self.crate_local_def_map.unwrap_or(&self.local_def_map)
     }
 
     /// Adds a definition of procedural macro `name` to the root module.
@@ -688,7 +689,7 @@ impl DefCollector<'_> {
         let vis = self
             .def_map
             .resolve_visibility(
-                self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+                self.crate_local_def_map.unwrap_or(&self.local_def_map),
                 self.db,
                 module_id,
                 vis,
@@ -731,7 +732,7 @@ impl DefCollector<'_> {
         names: Option<Vec<Name>>,
         extern_crate: Option<ExternCrateId>,
     ) {
-        let def_map = self.db.crate_def_map(krate);
+        let def_map = crate_def_map(self.db, krate);
         // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
         // macros.
         let root_scope = &def_map[DefMap::ROOT].scope;
@@ -811,32 +812,35 @@ impl DefCollector<'_> {
         let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db, Edition::LATEST))
             .entered();
         tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
-        let res = self.def_map.resolve_path_fp_with_macro(
-            self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
-            self.db,
-            ResolveMode::Import,
-            module_id,
-            &import.path,
-            BuiltinShadowMode::Module,
-            None, // An import may resolve to any kind of macro.
-        );
+        let ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info } =
+            self.def_map.resolve_path_fp_with_macro(
+                self.crate_local_def_map.unwrap_or(&self.local_def_map),
+                self.db,
+                ResolveMode::Import,
+                module_id,
+                &import.path,
+                BuiltinShadowMode::Module,
+                None, // An import may resolve to any kind of macro.
+            );
 
-        let def = res.resolved_def;
-        if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
+        if reached_fixedpoint == ReachedFixedPoint::No
+            || resolved_def.is_none()
+            || segment_index.is_some()
+        {
             return PartialResolvedImport::Unresolved;
         }
 
-        if res.prefix_info.differing_crate {
+        if prefix_info.differing_crate {
             return PartialResolvedImport::Resolved(
-                def.filter_visibility(|v| matches!(v, Visibility::Public)),
+                resolved_def.filter_visibility(|v| matches!(v, Visibility::Public)),
             );
         }
 
         // Check whether all namespaces are resolved.
-        if def.is_full() {
-            PartialResolvedImport::Resolved(def)
+        if resolved_def.is_full() {
+            PartialResolvedImport::Resolved(resolved_def)
         } else {
-            PartialResolvedImport::Indeterminate(def)
+            PartialResolvedImport::Indeterminate(resolved_def)
         }
     }
 
@@ -849,7 +853,7 @@ impl DefCollector<'_> {
         let vis = self
             .def_map
             .resolve_visibility(
-                self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+                self.crate_local_def_map.unwrap_or(&self.local_def_map),
                 self.db,
                 module_id,
                 &directive.import.visibility,
@@ -986,6 +990,43 @@ impl DefCollector<'_> {
                             Some(ImportOrExternCrate::Glob(glob)),
                         );
                     }
+                    Some(ModuleDefId::TraitId(it)) => {
+                        // FIXME: Implement this correctly
+                        // We can't actually call `trait_items`, the reason being that if macro calls
+                        // occur, they will call back into the def map which we might be computing right
+                        // now resulting in a cycle.
+                        // To properly implement this, trait item collection needs to be done in def map
+                        // collection...
+                        let resolutions = if true {
+                            vec![]
+                        } else {
+                            self.db
+                                .trait_items(it)
+                                .items
+                                .iter()
+                                .map(|&(ref name, variant)| {
+                                    let res = match variant {
+                                        AssocItemId::FunctionId(it) => {
+                                            PerNs::values(it.into(), vis, None)
+                                        }
+                                        AssocItemId::ConstId(it) => {
+                                            PerNs::values(it.into(), vis, None)
+                                        }
+                                        AssocItemId::TypeAliasId(it) => {
+                                            PerNs::types(it.into(), vis, None)
+                                        }
+                                    };
+                                    (Some(name.clone()), res)
+                                })
+                                .collect::<Vec<_>>()
+                        };
+                        self.update(
+                            module_id,
+                            &resolutions,
+                            vis,
+                            Some(ImportOrExternCrate::Glob(glob)),
+                        );
+                    }
                     Some(d) => {
                         tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
                     }
@@ -1240,7 +1281,7 @@ impl DefCollector<'_> {
             };
             let resolver = |path: &_| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
-                    self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+                    self.crate_local_def_map.unwrap_or(&self.local_def_map),
                     self.db,
                     ResolveMode::Other,
                     directive.module_id,
@@ -1307,7 +1348,7 @@ impl DefCollector<'_> {
                         );
                         // Record its helper attributes.
                         if def_id.krate != self.def_map.krate {
-                            let def_map = self.db.crate_def_map(def_id.krate);
+                            let def_map = crate_def_map(self.db, def_id.krate);
                             if let Some(helpers) = def_map.data.exported_derives.get(&def_id) {
                                 self.def_map
                                     .derive_helpers_in_scope
@@ -1553,7 +1594,7 @@ impl DefCollector<'_> {
                         self.def_map.krate,
                         |path| {
                             let resolved_res = self.def_map.resolve_path_fp_with_macro(
-                                self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+                                self.crate_local_def_map.unwrap_or(&self.local_def_map),
                                 self.db,
                                 ResolveMode::Other,
                                 directive.module_id,
@@ -1702,11 +1743,8 @@ impl ModCollector<'_, '_> {
 
             let module = self.def_collector.def_map.module_id(module_id);
             let def_map = &mut self.def_collector.def_map;
-            let local_def_map = self
-                .def_collector
-                .crate_local_def_map
-                .as_deref()
-                .unwrap_or(&self.def_collector.local_def_map);
+            let local_def_map =
+                self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
 
             match item {
                 ModItem::Mod(m) => self.collect_module(m, &attrs),
@@ -2133,10 +2171,7 @@ impl ModCollector<'_, '_> {
         let def_map = &mut self.def_collector.def_map;
         let vis = def_map
             .resolve_visibility(
-                self.def_collector
-                    .crate_local_def_map
-                    .as_deref()
-                    .unwrap_or(&self.def_collector.local_def_map),
+                self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map),
                 self.def_collector.db,
                 self.module_id,
                 visibility,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index a49155d878c..74ce33a6419 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -17,14 +17,17 @@ use hir_expand::{
     name::Name,
 };
 use span::Edition;
-use triomphe::Arc;
+use stdx::TupleExt;
 
 use crate::{
     AdtId, LocalModuleId, ModuleDefId,
     db::DefDatabase,
     item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
     item_tree::FieldsShape,
-    nameres::{BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, sub_namespace_match},
+    nameres::{
+        BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map,
+        sub_namespace_match,
+    },
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
 };
@@ -44,6 +47,7 @@ pub(super) enum ReachedFixedPoint {
 #[derive(Debug, Clone)]
 pub(super) struct ResolvePathResult {
     pub(super) resolved_def: PerNs,
+    /// The index of the last resolved segment, or `None` if the full path has been resolved.
     pub(super) segment_index: Option<usize>,
     pub(super) reached_fixedpoint: ReachedFixedPoint,
     pub(super) prefix_info: ResolvePathResultPrefixInfo,
@@ -173,7 +177,6 @@ impl DefMap {
             return result;
         }
 
-        let mut arc;
         let mut current_map = self;
 
         let mut merge = |new: ResolvePathResult| {
@@ -195,8 +198,7 @@ impl DefMap {
                 Some(block) if original_module == Self::ROOT => {
                     // Block modules "inherit" names from its parent module.
                     original_module = block.parent.local_id;
-                    arc = block.parent.def_map(db, current_map.krate);
-                    current_map = &arc;
+                    current_map = block.parent.def_map(db, current_map.krate);
                 }
                 // Proper (non-block) modules, including those in block `DefMap`s, don't.
                 _ => {
@@ -204,8 +206,7 @@ impl DefMap {
                         // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
                         // the prelude items (which are not inserted into blocks because they can be overridden there).
                         original_module = Self::ROOT;
-                        arc = db.crate_def_map(self.krate);
-                        current_map = &arc;
+                        current_map = crate_def_map(db, self.krate);
 
                         let new = current_map.resolve_path_fp_in_all_preludes(
                             local_def_map,
@@ -253,7 +254,7 @@ impl DefMap {
                     cov_mark::hit!(macro_dollar_crate_self);
                     PerNs::types(self.crate_root().into(), Visibility::Public, None)
                 } else {
-                    let def_map = db.crate_def_map(krate);
+                    let def_map = crate_def_map(db, krate);
                     let module = def_map.module_id(Self::ROOT);
                     cov_mark::hit!(macro_dollar_crate_other);
                     PerNs::types(module.into(), Visibility::Public, None)
@@ -312,7 +313,7 @@ impl DefMap {
                 // Adjust `local_id` to `self`, i.e. the nearest non-block module.
                 if def_map.module_id(local_id).is_block_module() {
                     (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
-                    def_map = &ext;
+                    def_map = ext;
                 }
 
                 // Go up the module tree but skip block modules as `super` always refers to the
@@ -325,7 +326,7 @@ impl DefMap {
                         if def_map.module_id(local_id).is_block_module() {
                             (ext, local_id) =
                                 adjust_to_nearest_non_block_module(db, def_map, local_id);
-                            def_map = &ext;
+                            def_map = ext;
                         }
                     } else {
                         stdx::always!(def_map.block.is_none());
@@ -364,7 +365,15 @@ impl DefMap {
             },
         };
 
-        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+        self.resolve_remaining_segments(
+            db,
+            mode,
+            segments,
+            curr_per_ns,
+            path,
+            shadow,
+            original_module,
+        )
     }
 
     /// Resolves a path only in the preludes, without accounting for item scopes.
@@ -413,7 +422,15 @@ impl DefMap {
             }
         };
 
-        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+        self.resolve_remaining_segments(
+            db,
+            mode,
+            segments,
+            curr_per_ns,
+            path,
+            shadow,
+            original_module,
+        )
     }
 
     /// 2018-style absolute path -- only extern prelude
@@ -441,10 +458,11 @@ impl DefMap {
 
     fn resolve_remaining_segments<'a>(
         &self,
+        db: &dyn DefDatabase,
+        mode: ResolveMode,
         mut segments: impl Iterator<Item = (usize, &'a Name)>,
         mut curr_per_ns: PerNs,
         path: &ModPath,
-        db: &dyn DefDatabase,
         shadow: BuiltinShadowMode,
         original_module: LocalModuleId,
     ) -> ResolvePathResult {
@@ -465,6 +483,7 @@ impl DefMap {
             curr_per_ns = match curr.def {
                 ModuleDefId::ModuleId(module) => {
                     if module.krate != self.krate {
+                        // FIXME: Inefficient
                         let path = ModPath::from_segments(
                             PathKind::SELF,
                             path.segments()[i..].iter().cloned(),
@@ -478,7 +497,7 @@ impl DefMap {
                         let resolution = defp_map.resolve_path_fp_with_macro(
                             LocalDefMap::EMPTY,
                             db,
-                            ResolveMode::Other,
+                            mode,
                             module.local_id,
                             &path,
                             shadow,
@@ -553,6 +572,44 @@ impl DefMap {
                         ),
                     };
                 }
+                def @ ModuleDefId::TraitId(t) if mode == ResolveMode::Import => {
+                    // FIXME: Implement this correctly
+                    // We can't actually call `trait_items`, the reason being that if macro calls
+                    // occur, they will call back into the def map which we might be computing right
+                    // now resulting in a cycle.
+                    // To properly implement this, trait item collection needs to be done in def map
+                    // collection...
+                    let item =
+                        if true { None } else { db.trait_items(t).assoc_item_by_name(segment) };
+                    return match item {
+                        Some(item) => ResolvePathResult::new(
+                            match item {
+                                crate::AssocItemId::FunctionId(function_id) => PerNs::values(
+                                    function_id.into(),
+                                    curr.vis,
+                                    curr.import.and_then(|it| it.import_or_glob()),
+                                ),
+                                crate::AssocItemId::ConstId(const_id) => PerNs::values(
+                                    const_id.into(),
+                                    curr.vis,
+                                    curr.import.and_then(|it| it.import_or_glob()),
+                                ),
+                                crate::AssocItemId::TypeAliasId(type_alias_id) => {
+                                    PerNs::types(type_alias_id.into(), curr.vis, curr.import)
+                                }
+                            },
+                            ReachedFixedPoint::Yes,
+                            segments.next().map(TupleExt::head),
+                            ResolvePathResultPrefixInfo::default(),
+                        ),
+                        None => ResolvePathResult::new(
+                            PerNs::types(def, curr.vis, curr.import),
+                            ReachedFixedPoint::Yes,
+                            Some(i),
+                            ResolvePathResultPrefixInfo::default(),
+                        ),
+                    };
+                }
                 s => {
                     // could be an inherent method call in UFCS form
                     // (`Struct::method`), or some other kind of associated item
@@ -715,7 +772,7 @@ impl DefMap {
             } else {
                 // Extend lifetime
                 keep = prelude.def_map(db);
-                &keep
+                keep
             };
             def_map[prelude.local_id].scope.get(name)
         } else {
@@ -725,25 +782,23 @@ impl DefMap {
 }
 
 /// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to.
-fn adjust_to_nearest_non_block_module(
-    db: &dyn DefDatabase,
-    def_map: &DefMap,
+fn adjust_to_nearest_non_block_module<'db>(
+    db: &'db dyn DefDatabase,
+    def_map: &'db DefMap,
     mut local_id: LocalModuleId,
-) -> (Arc<DefMap>, LocalModuleId) {
+) -> (&'db DefMap, LocalModuleId) {
     // INVARIANT: `local_id` in `def_map` must be a block module.
     stdx::always!(def_map.module_id(local_id).is_block_module());
 
-    let mut ext;
     // This needs to be a local variable due to our mighty lifetime.
     let mut def_map = def_map;
     loop {
         let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
 
-        ext = parent.def_map(db, def_map.krate);
-        def_map = &ext;
+        def_map = parent.def_map(db, def_map.krate);
         local_id = parent.local_id;
         if !parent.is_block_module() {
-            return (ext, local_id);
+            return (def_map, local_id);
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 3fd095a9a98..4a7974c4fa1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -7,20 +7,25 @@ mod primitives;
 use base_db::RootQueryDb;
 use expect_test::{Expect, expect};
 use test_fixture::WithFixture;
-use triomphe::Arc;
 
-use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
+use crate::{
+    nameres::{DefMap, crate_def_map},
+    test_db::TestDB,
+};
 
-fn compute_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Arc<DefMap> {
+fn compute_crate_def_map(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    cb: impl FnOnce(&DefMap),
+) {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
-    db.crate_def_map(krate)
+    cb(crate_def_map(&db, krate));
 }
 
 fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.fetch_test_crate();
-    db.crate_def_map(krate).dump(&db)
+    crate_def_map(&db, krate).dump(&db)
 }
 
 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 179a9c8fec2..948e8bed66d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -7,24 +7,37 @@ use span::Edition;
 use test_fixture::WithFixture;
 use triomphe::Arc;
 
-use crate::{AdtId, ModuleDefId, db::DefDatabase, nameres::tests::TestDB};
+use crate::{
+    AdtId, ModuleDefId,
+    db::DefDatabase,
+    nameres::{crate_def_map, tests::TestDB},
+};
 
-fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
+fn check_def_map_is_not_recomputed(
+    #[rust_analyzer::rust_fixture] ra_fixture_initial: &str,
+    #[rust_analyzer::rust_fixture] ra_fixture_change: &str,
+) {
     let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
     let krate = db.fetch_test_crate();
     {
         let events = db.log_executed(|| {
-            db.crate_def_map(krate);
+            crate_def_map(&db, krate);
         });
-        assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}")
+        assert!(
+            format!("{events:?}").contains("crate_local_def_map"),
+            "no crate def map computed:\n{events:#?}",
+        )
     }
     db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change);
 
     {
         let events = db.log_executed(|| {
-            db.crate_def_map(krate);
+            crate_def_map(&db, krate);
         });
-        assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}")
+        assert!(
+            !format!("{events:?}").contains("crate_local_def_map"),
+            "crate def map invalidated:\n{events:#?}",
+        )
     }
 }
 
@@ -44,7 +57,7 @@ pub const BAZ: u32 = 0;
     );
 
     for &krate in db.all_crates().iter() {
-        db.crate_def_map(krate);
+        crate_def_map(&db, krate);
     }
 
     let all_crates_before = db.all_crates();
@@ -94,11 +107,11 @@ pub const BAZ: u32 = 0;
 
     let events = db.log_executed(|| {
         for &krate in db.all_crates().iter() {
-            db.crate_def_map(krate);
+            crate_def_map(&db, krate);
         }
     });
     let invalidated_def_maps =
-        events.iter().filter(|event| event.contains("crate_def_map")).count();
+        events.iter().filter(|event| event.contains("crate_local_def_map")).count();
     assert_eq!(invalidated_def_maps, 1, "{events:#?}")
 }
 
@@ -330,7 +343,7 @@ m!(Z);
     let krate = db.test_crate();
     {
         let events = db.log_executed(|| {
-            let crate_def_map = db.crate_def_map(krate);
+            let crate_def_map = crate_def_map(&db, krate);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
         });
@@ -352,7 +365,7 @@ m!(Z);
 
     {
         let events = db.log_executed(|| {
-            let crate_def_map = db.crate_def_map(krate);
+            let crate_def_map = crate_def_map(&db, krate);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
         });
@@ -403,7 +416,7 @@ pub type Ty = ();
 
     {
         let events = db.log_executed(|| {
-            let crate_def_map = db.crate_def_map(krate);
+            let crate_def_map = crate_def_map(&db, krate);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 8);
             assert_eq!(module_data.scope.impls().count(), 1);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index 5f8a01523d8..3cba88ec2f1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -736,7 +736,7 @@ pub struct bar;
 
 #[test]
 fn macro_dollar_crate_is_correct_in_derive_meta() {
-    let map = compute_crate_def_map(
+    compute_crate_def_map(
         r#"
 //- minicore: derive, clone
 //- /main.rs crate:main deps:lib
@@ -753,13 +753,13 @@ macro_rules! foo {
 
 pub use core::clone::Clone;
 "#,
+        |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
     );
-    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
 fn expand_derive() {
-    let map = compute_crate_def_map(
+    compute_crate_def_map(
         r#"
 //- /main.rs crate:main deps:core
 use core::Copy;
@@ -775,8 +775,8 @@ pub macro Copy {}
 #[rustc_builtin_macro]
 pub macro Clone {}
 "#,
+        |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2),
     );
-    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2);
 }
 
 #[test]
@@ -803,7 +803,7 @@ pub trait Clone {}
 fn builtin_derive_with_unresolved_attributes_fall_back() {
     // Tests that we still resolve derives after ignoring an unresolved attribute.
     cov_mark::check!(unresolved_attribute_fallback);
-    let map = compute_crate_def_map(
+    compute_crate_def_map(
         r#"
 //- /main.rs crate:main deps:core
 use core::{Clone, derive};
@@ -818,8 +818,8 @@ pub macro derive($item:item) {}
 #[rustc_builtin_macro]
 pub macro Clone {}
 "#,
+        |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
     );
-    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
@@ -1096,7 +1096,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
 "#,
     );
     let krate = *db.all_crates().last().expect("no crate graph present");
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
 
     assert_eq!(def_map.data.exported_derives.len(), 1);
     match def_map.data.exported_derives.values().next() {
@@ -1446,7 +1446,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
     "#,
     );
     let krate = *db.all_crates().last().expect("no crate graph present");
-    let def_map = db.crate_def_map(krate);
+    let def_map = crate_def_map(&db, krate);
 
     let root_module = &def_map[DefMap::ROOT].scope;
     assert!(
@@ -1544,7 +1544,7 @@ macro_rules! mk_foo {
 
 #[test]
 fn macro_sub_namespace() {
-    let map = compute_crate_def_map(
+    compute_crate_def_map(
         r#"
 //- minicore: derive, clone
 macro_rules! Clone { () => {} }
@@ -1553,8 +1553,8 @@ macro_rules! derive { () => {} }
 #[derive(Clone)]
 struct S;
     "#,
+        |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
     );
-    assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index 071b55c83d8..9c97e42f4fd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -839,6 +839,7 @@ mod foo;
 #[path = "./foo.rs"]
 mod foo;
 "#,
+        |_| (),
     );
 
     compute_crate_def_map(
@@ -852,6 +853,7 @@ mod bar;
 #[path = "./foo.rs"]
 mod foo;
 "#,
+        |_| (),
     );
 }
 
@@ -894,3 +896,149 @@ struct AlsoShouldNotAppear;
         "#]],
     )
 }
+
+#[test]
+fn invalid_imports() {
+    check(
+        r#"
+//- /main.rs
+mod module;
+
+use self::module::S::new;
+use self::module::unresolved;
+use self::module::C::const_based;
+use self::module::Enum::Variant::NoAssoc;
+
+//- /module.rs
+pub struct S;
+impl S {
+    pub fn new() {}
+}
+pub const C: () = ();
+pub enum Enum {
+    Variant,
+}
+        "#,
+        expect![[r#"
+            crate
+            NoAssoc: _
+            const_based: _
+            module: t
+            new: _
+            unresolved: _
+
+            crate::module
+            C: v
+            Enum: t
+            S: t v
+        "#]],
+    );
+}
+
+#[test]
+fn trait_item_imports_same_crate() {
+    check(
+        r#"
+//- /main.rs
+mod module;
+
+use self::module::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
+
+//- /module.rs
+macro_rules! m {
+    ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+    type AssocType;
+    const ASSOC_CONST: ();
+    fn method(&self);
+    m!(MACRO_CONST);
+}
+        "#,
+        expect![[r#"
+            crate
+            ASSOC_CONST: _
+            AssocType: _
+            MACRO_CONST: _
+            method: _
+            module: t
+
+            crate::module
+            Trait: t
+        "#]],
+    );
+    check(
+        r#"
+//- /main.rs
+mod module;
+
+use self::module::Trait::*;
+
+//- /module.rs
+macro_rules! m {
+    ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+    type AssocType;
+    const ASSOC_CONST: ();
+    fn method(&self);
+    m!(MACRO_CONST);
+}
+        "#,
+        expect![[r#"
+            crate
+            module: t
+
+            crate::module
+            Trait: t
+        "#]],
+    );
+}
+
+#[test]
+fn trait_item_imports_differing_crate() {
+    check(
+        r#"
+//- /main.rs deps:lib crate:main
+use lib::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
+
+//- /lib.rs crate:lib
+macro_rules! m {
+    ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+    type AssocType;
+    const ASSOC_CONST: ();
+    fn method(&self);
+    m!(MACRO_CONST);
+}
+        "#,
+        expect![[r#"
+            crate
+            ASSOC_CONST: _
+            AssocType: _
+            MACRO_CONST: _
+            method: _
+        "#]],
+    );
+    check(
+        r#"
+//- /main.rs deps:lib crate:main
+use lib::Trait::*;
+
+//- /lib.rs crate:lib
+macro_rules! m {
+    ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+    type AssocType;
+    const ASSOC_CONST: ();
+    fn method(&self);
+    m!(MACRO_CONST);
+}
+        "#,
+        expect![[r#"
+            crate
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 8a8d17018c1..16988ddf04b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -34,30 +34,30 @@ use crate::{
     item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
     item_tree::ImportAlias,
     lang_item::LangItemTarget,
-    nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo},
+    nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
     per_ns::PerNs,
     type_ref::LifetimeRef,
     visibility::{RawVisibility, Visibility},
 };
 
 #[derive(Debug, Clone)]
-pub struct Resolver {
+pub struct Resolver<'db> {
     /// The stack of scopes, where the inner-most scope is the last item.
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
-    scopes: Vec<Scope>,
-    module_scope: ModuleItemMap,
+    scopes: Vec<Scope<'db>>,
+    module_scope: ModuleItemMap<'db>,
 }
 
 #[derive(Clone)]
-struct ModuleItemMap {
-    def_map: Arc<DefMap>,
-    local_def_map: Arc<LocalDefMap>,
+struct ModuleItemMap<'db> {
+    def_map: &'db DefMap,
+    local_def_map: &'db LocalDefMap,
     module_id: LocalModuleId,
 }
 
-impl fmt::Debug for ModuleItemMap {
+impl fmt::Debug for ModuleItemMap<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish()
     }
@@ -80,9 +80,9 @@ impl fmt::Debug for ExprScope {
 }
 
 #[derive(Debug, Clone)]
-enum Scope {
+enum Scope<'db> {
     /// All the items and imported names of a module
-    BlockScope(ModuleItemMap),
+    BlockScope(ModuleItemMap<'db>),
     /// Brings the generic parameters of an item into scope as well as the `Self` type alias /
     /// generic for ADTs and impls.
     GenericParams { def: GenericDefId, params: Arc<GenericParams> },
@@ -133,7 +133,7 @@ pub enum LifetimeNs {
     LifetimeParam(LifetimeParamId),
 }
 
-impl Resolver {
+impl<'db> Resolver<'db> {
     /// Resolve known trait from std, like `std::futures::Future`
     pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
         let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
@@ -580,7 +580,7 @@ impl Resolver {
         for scope in self.scopes() {
             scope.process_names(&mut res, db);
         }
-        let ModuleItemMap { ref def_map, module_id, ref local_def_map } = self.module_scope;
+        let ModuleItemMap { def_map, module_id, local_def_map } = self.module_scope;
         // FIXME: should we provide `self` here?
         // f(
         //     Name::self_param(),
@@ -842,14 +842,14 @@ impl Resolver {
     #[must_use]
     pub fn update_to_inner_scope(
         &mut self,
-        db: &dyn DefDatabase,
+        db: &'db dyn DefDatabase,
         owner: DefWithBodyId,
         expr_id: ExprId,
     ) -> UpdateGuard {
         #[inline(always)]
-        fn append_expr_scope(
-            db: &dyn DefDatabase,
-            resolver: &mut Resolver,
+        fn append_expr_scope<'db>(
+            db: &'db dyn DefDatabase,
+            resolver: &mut Resolver<'db>,
             owner: DefWithBodyId,
             expr_scopes: &Arc<ExprScopes>,
             scope_id: ScopeId,
@@ -863,7 +863,7 @@ impl Resolver {
                 scope_id,
             }));
             if let Some(block) = expr_scopes.block(scope_id) {
-                let def_map = db.block_def_map(block);
+                let def_map = block_def_map(db, block);
                 let local_def_map = block.lookup(db).module.only_local_def_map(db);
                 resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
                     def_map,
@@ -945,8 +945,8 @@ fn hygiene_info(
 
 pub struct UpdateGuard(usize);
 
-impl Resolver {
-    fn scopes(&self) -> impl Iterator<Item = &Scope> {
+impl<'db> Resolver<'db> {
+    fn scopes(&self) -> impl Iterator<Item = &Scope<'db>> {
         self.scopes.iter().rev()
     }
 
@@ -970,12 +970,12 @@ impl Resolver {
     fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
         self.scopes()
             .find_map(|scope| match scope {
-                Scope::BlockScope(m) => Some((&*m.def_map, &*m.local_def_map, m.module_id)),
+                Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)),
                 _ => None,
             })
             .unwrap_or((
-                &self.module_scope.def_map,
-                &self.module_scope.local_def_map,
+                self.module_scope.def_map,
+                self.module_scope.local_def_map,
                 self.module_scope.module_id,
             ))
     }
@@ -992,8 +992,8 @@ pub enum ScopeDef {
     Label(LabelId),
 }
 
-impl Scope {
-    fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
+impl<'db> Scope<'db> {
+    fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) {
         match self {
             Scope::BlockScope(m) => {
                 m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
@@ -1047,7 +1047,11 @@ impl Scope {
     }
 }
 
-pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
+pub fn resolver_for_expr(
+    db: &dyn DefDatabase,
+    owner: DefWithBodyId,
+    expr_id: ExprId,
+) -> Resolver<'_> {
     let r = owner.resolver(db);
     let scopes = db.expr_scopes(owner);
     let scope_id = scopes.scope_for(expr_id);
@@ -1058,25 +1062,25 @@ pub fn resolver_for_scope(
     db: &dyn DefDatabase,
     owner: DefWithBodyId,
     scope_id: Option<ScopeId>,
-) -> Resolver {
+) -> Resolver<'_> {
     let r = owner.resolver(db);
     let scopes = db.expr_scopes(owner);
     resolver_for_scope_(db, scopes, scope_id, r, owner)
 }
 
-fn resolver_for_scope_(
-    db: &dyn DefDatabase,
+fn resolver_for_scope_<'db>(
+    db: &'db dyn DefDatabase,
     scopes: Arc<ExprScopes>,
     scope_id: Option<ScopeId>,
-    mut r: Resolver,
+    mut r: Resolver<'db>,
     owner: DefWithBodyId,
-) -> Resolver {
+) -> Resolver<'db> {
     let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
     r.scopes.reserve(scope_chain.len());
 
     for scope in scope_chain.into_iter().rev() {
         if let Some(block) = scopes.block(scope) {
-            let def_map = db.block_def_map(block);
+            let def_map = block_def_map(db, block);
             let local_def_map = block.lookup(db).module.only_local_def_map(db);
             r = r.push_block_scope(def_map, local_def_map);
             // FIXME: This adds as many module scopes as there are blocks, but resolving in each
@@ -1092,18 +1096,26 @@ fn resolver_for_scope_(
     r
 }
 
-impl Resolver {
-    fn push_scope(mut self, scope: Scope) -> Resolver {
+impl<'db> Resolver<'db> {
+    fn push_scope(mut self, scope: Scope<'db>) -> Resolver<'db> {
         self.scopes.push(scope);
         self
     }
 
-    fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver {
+    fn push_generic_params_scope(
+        self,
+        db: &'db dyn DefDatabase,
+        def: GenericDefId,
+    ) -> Resolver<'db> {
         let params = db.generic_params(def);
         self.push_scope(Scope::GenericParams { def, params })
     }
 
-    fn push_block_scope(self, def_map: Arc<DefMap>, local_def_map: Arc<LocalDefMap>) -> Resolver {
+    fn push_block_scope(
+        self,
+        def_map: &'db DefMap,
+        local_def_map: &'db LocalDefMap,
+    ) -> Resolver<'db> {
         self.push_scope(Scope::BlockScope(ModuleItemMap {
             def_map,
             local_def_map,
@@ -1116,19 +1128,19 @@ impl Resolver {
         owner: DefWithBodyId,
         expr_scopes: Arc<ExprScopes>,
         scope_id: ScopeId,
-    ) -> Resolver {
+    ) -> Resolver<'db> {
         self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
     }
 }
 
-impl ModuleItemMap {
+impl<'db> ModuleItemMap<'db> {
     fn resolve_path_in_value_ns(
         &self,
-        db: &dyn DefDatabase,
+        db: &'db dyn DefDatabase,
         path: &ModPath,
     ) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
         let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally(
-            &self.local_def_map,
+            self.local_def_map,
             db,
             self.module_id,
             path,
@@ -1167,7 +1179,7 @@ impl ModuleItemMap {
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
     {
         let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally(
-            &self.local_def_map,
+            self.local_def_map,
             db,
             self.module_id,
             path,
@@ -1263,11 +1275,11 @@ impl ScopeNames {
 
 pub trait HasResolver: Copy {
     /// Builds a resolver for type references inside this def.
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver;
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_>;
 }
 
 impl HasResolver for ModuleId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         let (mut def_map, local_def_map) = self.local_def_map(db);
         let mut module_id = self.local_id;
 
@@ -1289,21 +1301,17 @@ impl HasResolver for ModuleId {
         }
         let mut resolver = Resolver {
             scopes: Vec::with_capacity(modules.len()),
-            module_scope: ModuleItemMap {
-                def_map,
-                local_def_map: local_def_map.clone(),
-                module_id,
-            },
+            module_scope: ModuleItemMap { def_map, local_def_map, module_id },
         };
         for def_map in modules.into_iter().rev() {
-            resolver = resolver.push_block_scope(def_map, local_def_map.clone());
+            resolver = resolver.push_block_scope(def_map, local_def_map);
         }
         resolver
     }
 }
 
 impl HasResolver for CrateRootModuleId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         let (def_map, local_def_map) = self.local_def_map(db);
         Resolver {
             scopes: vec![],
@@ -1313,75 +1321,75 @@ impl HasResolver for CrateRootModuleId {
 }
 
 impl HasResolver for TraitId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for TraitAliasId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl<T: Into<AdtId> + Copy> HasResolver for T {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         let def = self.into();
         def.module(db).resolver(db).push_generic_params_scope(db, def.into())
     }
 }
 
 impl HasResolver for FunctionId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for ConstId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for StaticId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for TypeAliasId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for ImplId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for ExternBlockId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         // Same as parent's
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for ExternCrateId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for UseId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for DefWithBodyId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         match self {
             DefWithBodyId::ConstId(c) => c.resolver(db),
             DefWithBodyId::FunctionId(f) => f.resolver(db),
@@ -1392,7 +1400,7 @@ impl HasResolver for DefWithBodyId {
 }
 
 impl HasResolver for ItemContainerId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         match self {
             ItemContainerId::ModuleId(it) => it.resolver(db),
             ItemContainerId::TraitId(it) => it.resolver(db),
@@ -1403,7 +1411,7 @@ impl HasResolver for ItemContainerId {
 }
 
 impl HasResolver for GenericDefId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         match self {
             GenericDefId::FunctionId(inner) => inner.resolver(db),
             GenericDefId::AdtId(adt) => adt.resolver(db),
@@ -1418,13 +1426,13 @@ impl HasResolver for GenericDefId {
 }
 
 impl HasResolver for EnumVariantId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         self.lookup(db).parent.resolver(db)
     }
 }
 
 impl HasResolver for VariantId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         match self {
             VariantId::EnumVariantId(it) => it.resolver(db),
             VariantId::StructId(it) => it.resolver(db),
@@ -1434,7 +1442,7 @@ impl HasResolver for VariantId {
 }
 
 impl HasResolver for MacroId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         match self {
             MacroId::Macro2Id(it) => it.resolver(db),
             MacroId::MacroRulesId(it) => it.resolver(db),
@@ -1444,29 +1452,29 @@ impl HasResolver for MacroId {
 }
 
 impl HasResolver for Macro2Id {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for ProcMacroId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for MacroRulesId {
-    fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+    fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
         lookup_resolver(db, self)
     }
 }
 
-fn lookup_resolver<'db>(
-    db: &(dyn DefDatabase + 'db),
+fn lookup_resolver(
+    db: &dyn DefDatabase,
     lookup: impl Lookup<
         Database = dyn DefDatabase,
         Data = impl ItemTreeLoc<Container = impl HasResolver>,
     >,
-) -> Resolver {
+) -> Resolver<'_> {
     lookup.lookup(db).container().resolver(db)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 47097548295..6c995ab6c23 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -15,7 +15,7 @@ use triomphe::Arc;
 use crate::{
     LocalModuleId, Lookup, ModuleDefId, ModuleId,
     db::DefDatabase,
-    nameres::{DefMap, ModuleSource},
+    nameres::{DefMap, ModuleSource, block_def_map, crate_def_map},
     src::HasSource,
 };
 
@@ -133,7 +133,7 @@ impl TestDB {
 
     pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
         for &krate in self.relevant_crates(file_id).iter() {
-            let crate_def_map = self.crate_def_map(krate);
+            let crate_def_map = crate_def_map(self, krate);
             for (local_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
                     return crate_def_map.module_id(local_id);
@@ -146,16 +146,16 @@ impl TestDB {
     pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
         let file_module = self.module_for_file(position.file_id.file_id(self));
         let mut def_map = file_module.def_map(self);
-        let module = self.mod_at_position(&def_map, position);
+        let module = self.mod_at_position(def_map, position);
 
-        def_map = match self.block_at_position(&def_map, position) {
+        def_map = match self.block_at_position(def_map, position) {
             Some(it) => it,
             None => return def_map.module_id(module),
         };
         loop {
-            let new_map = self.block_at_position(&def_map, position);
+            let new_map = self.block_at_position(def_map, position);
             match new_map {
-                Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => {
+                Some(new_block) if !std::ptr::eq(&new_block, &def_map) => {
                     def_map = new_block;
                 }
                 _ => {
@@ -206,7 +206,7 @@ impl TestDB {
         res
     }
 
-    fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
+    fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<&DefMap> {
         // Find the smallest (innermost) function in `def_map` containing the cursor.
         let mut size = None;
         let mut fn_def = None;
@@ -263,7 +263,7 @@ impl TestDB {
             let mut containing_blocks =
                 scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope));
 
-            if let Some(block) = containing_blocks.next().map(|block| self.block_def_map(block)) {
+            if let Some(block) = containing_blocks.next().map(|block| block_def_map(self, block)) {
                 return Some(block);
             }
         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index b42c8d383d4..3c67ee9fe5b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -28,7 +28,7 @@ pub enum Visibility {
 impl Visibility {
     pub fn resolve(
         db: &dyn DefDatabase,
-        resolver: &crate::resolver::Resolver,
+        resolver: &crate::resolver::Resolver<'_>,
         raw_vis: &RawVisibility,
     ) -> Self {
         // we fall back to public visibility (i.e. fail open) if the path can't be resolved
@@ -50,7 +50,7 @@ impl Visibility {
             return false;
         }
         let def_map = from_module.def_map(db);
-        Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id)
+        Self::is_visible_from_def_map_(db, def_map, to_module, from_module.local_id)
     }
 
     pub(crate) fn is_visible_from_def_map(
@@ -116,7 +116,7 @@ impl Visibility {
                     match def_map.parent() {
                         Some(module) => {
                             parent_arc = module.def_map(db);
-                            def_map = &*parent_arc;
+                            def_map = parent_arc;
                             from_module = module.local_id;
                         }
                         // Reached the root module, nothing left to check.
@@ -257,7 +257,7 @@ pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId
 }
 
 #[inline]
-fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver, trait_id: TraitId) -> Visibility {
+fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
     let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
     let item_tree = tree_id.item_tree(db);
     let tr_def = &item_tree[tree_id.value];
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index bb17eb06276..94c97713f06 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -1,4 +1,5 @@
 //! A higher level attributes based on TokenTree, with also some shortcuts.
+use std::iter;
 use std::{borrow::Cow, fmt, ops};
 
 use base_db::Crate;
@@ -122,16 +123,15 @@ impl RawAttrs {
             (None, entries @ Some(_)) => Self { entries },
             (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
+                let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1);
                 let items = a
                     .slice
                     .iter()
                     .cloned()
                     .chain(b.slice.iter().map(|it| {
                         let mut it = it.clone();
-                        it.id.id = (it.id.ast_index() as u32 + last_ast_index)
-                            | ((it.id.cfg_attr_index().unwrap_or(0) as u32)
-                                << AttrId::AST_INDEX_BITS);
+                        let id = it.id.ast_index() + last_ast_index;
+                        it.id = AttrId::new(id, it.id.is_inner_attr());
                         it
                     }))
                     .collect::<Vec<_>>();
@@ -175,25 +175,20 @@ pub struct AttrId {
 // FIXME: This only handles a single level of cfg_attr nesting
 // that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
 impl AttrId {
-    const CFG_ATTR_BITS: usize = 7;
-    const AST_INDEX_MASK: usize = 0x00FF_FFFF;
-    const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize;
-    const CFG_ATTR_SET_BITS: u32 = 1 << 31;
+    const INNER_ATTR_SET_BIT: u32 = 1 << 31;
 
-    pub fn ast_index(&self) -> usize {
-        self.id as usize & Self::AST_INDEX_MASK
+    pub fn new(id: usize, is_inner: bool) -> Self {
+        assert!(id <= !Self::INNER_ATTR_SET_BIT as usize);
+        let id = id as u32;
+        Self { id: if is_inner { id | Self::INNER_ATTR_SET_BIT } else { id } }
     }
 
-    pub fn cfg_attr_index(&self) -> Option<usize> {
-        if self.id & Self::CFG_ATTR_SET_BITS == 0 {
-            None
-        } else {
-            Some(self.id as usize >> Self::AST_INDEX_BITS)
-        }
+    pub fn ast_index(&self) -> usize {
+        (self.id & !Self::INNER_ATTR_SET_BIT) as usize
     }
 
-    pub fn with_cfg_attr(self, idx: usize) -> AttrId {
-        AttrId { id: self.id | ((idx as u32) << Self::AST_INDEX_BITS) | Self::CFG_ATTR_SET_BITS }
+    pub fn is_inner_attr(&self) -> bool {
+        self.id & Self::INNER_ATTR_SET_BIT != 0
     }
 }
 
@@ -333,10 +328,7 @@ impl Attr {
             None => return smallvec![self.clone()],
         };
         let index = self.id;
-        let attrs = parts
-            .enumerate()
-            .take(1 << AttrId::CFG_ATTR_BITS)
-            .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
+        let attrs = parts.filter_map(|attr| Attr::from_tt(db, attr, index));
 
         let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
         let cfg = CfgExpr::parse(&cfg);
@@ -467,13 +459,18 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
 pub fn collect_attrs(
     owner: &dyn ast::HasAttrs,
 ) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
-    let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
-    let outer_attrs =
-        ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
+    let inner_attrs =
+        inner_attributes(owner.syntax()).into_iter().flatten().zip(iter::repeat(true));
+    let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
+        .filter(|el| match el {
             Either::Left(attr) => attr.kind().is_outer(),
             Either::Right(comment) => comment.is_outer(),
-        });
-    outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr))
+        })
+        .zip(iter::repeat(false));
+    outer_attrs
+        .chain(inner_attrs)
+        .enumerate()
+        .map(|(id, (attr, is_inner))| (AttrId::new(id, is_inner), attr))
 }
 
 fn inner_attributes(
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
index 68283b916d7..d135584a080 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
@@ -1,5 +1,6 @@
 //! Builtin derives.
 
+use either::Either;
 use intern::sym;
 use itertools::{Itertools, izip};
 use parser::SyntaxKind;
@@ -1179,10 +1180,10 @@ fn coerce_pointee_expand(
                 };
                 new_predicates.push(
                     make::where_pred(
-                        make::ty_path(make::path_from_segments(
+                        Either::Right(make::ty_path(make::path_from_segments(
                             [make::path_segment(new_bounds_target)],
                             false,
-                        )),
+                        ))),
                         new_bounds,
                     )
                     .clone_for_update(),
@@ -1245,7 +1246,9 @@ fn coerce_pointee_expand(
                             substitute_type_in_bound(ty, &pointee_param_name.text(), ADDED_PARAM)
                         })
                     });
-                new_predicates.push(make::where_pred(pred_target, new_bounds).clone_for_update());
+                new_predicates.push(
+                    make::where_pred(Either::Right(pred_target), new_bounds).clone_for_update(),
+                );
             }
         }
 
@@ -1260,10 +1263,10 @@ fn coerce_pointee_expand(
         // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
         where_clause.add_predicate(
             make::where_pred(
-                make::ty_path(make::path_from_segments(
+                Either::Right(make::ty_path(make::path_from_segments(
                     [make::path_segment(make::name_ref(&pointee_param_name.text()))],
                     false,
-                )),
+                ))),
                 [make::type_bound(make::ty_path(make::path_from_segments(
                     [
                         make::path_segment(make::name_ref("core")),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 621e174cac9..539c7277284 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -452,7 +452,10 @@ fn concat_expand(
         Some(_) => (),
         None => span = Some(s),
     };
-    for (i, mut t) in tt.iter().enumerate() {
+
+    let mut i = 0;
+    let mut iter = tt.iter();
+    while let Some(mut t) = iter.next() {
         // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
         // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
         // implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
@@ -504,10 +507,40 @@ fn concat_expand(
                 record_span(id.span);
             }
             TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
+            // handle negative numbers
+            TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 0 && punct.char == '-' => {
+                let t = match iter.next() {
+                    Some(t) => t,
+                    None => {
+                        err.get_or_insert(ExpandError::other(
+                            call_site,
+                            "unexpected end of input after '-'",
+                        ));
+                        break;
+                    }
+                };
+
+                match t {
+                    TtElement::Leaf(tt::Leaf::Literal(it))
+                        if matches!(it.kind, tt::LitKind::Integer | tt::LitKind::Float) =>
+                    {
+                        format_to!(text, "-{}", it.symbol.as_str());
+                        record_span(punct.span.cover(it.span));
+                    }
+                    _ => {
+                        err.get_or_insert(ExpandError::other(
+                            call_site,
+                            "expected integer or floating pointer number after '-'",
+                        ));
+                        break;
+                    }
+                }
+            }
             _ => {
                 err.get_or_insert(ExpandError::other(call_site, "unexpected token"));
             }
         }
+        i += 1;
     }
     let span = span.unwrap_or_else(|| tt.top_subtree().delimiter.open);
     ExpandResult { value: quote!(span =>#text), err }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 8a1a33d7e3b..1cd975b980d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -19,18 +19,8 @@ pub enum ProcMacroKind {
     Attr,
 }
 
-pub trait AsAny: Any {
-    fn as_any(&self) -> &dyn Any;
-}
-
-impl<T: Any> AsAny for T {
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-}
-
 /// A proc-macro expander implementation.
-pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
+pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
     /// Run the expander with the given input subtree, optional attribute input subtree (for
     /// [`ProcMacroKind::Attr`]), environment variables, and span information.
     fn expand(
@@ -44,7 +34,9 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
         current_dir: String,
     ) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
 
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == self.type_id()
+    }
 }
 
 impl PartialEq for dyn ProcMacroExpander {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index d1a1e135fff..f903b06d65e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -91,7 +91,7 @@ impl From<MirEvalError> for ConstEvalError {
 
 pub(crate) fn path_to_const<'g>(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     path: &Path,
     mode: ParamLoweringMode,
     args: impl FnOnce() -> &'g Generics,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 57106412765..e4a23cbbacf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -480,7 +480,7 @@ struct FilterMapNextChecker {
 }
 
 impl FilterMapNextChecker {
-    fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
+    fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
         // Find and store the FunctionIds for Iterator::filter_map and Iterator::next
         let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
             .resolve_function(db, resolver.krate())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 068fc22f2ca..785277d70c6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -73,7 +73,7 @@ pub(crate) struct MatchCheckCtx<'db> {
 
 impl<'db> MatchCheckCtx<'db> {
     pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
-        let def_map = db.crate_def_map(module.krate());
+        let def_map = module.crate_def_map(db);
         let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
         Self { module, body, db, exhaustive_patterns }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 73b99db7268..20cf3c78115 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -7,7 +7,7 @@ use either::Either;
 use hir_def::{
     AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
     expr_store::{Body, path::Path},
-    hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
+    hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
     resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
     signatures::StaticFlags,
     type_ref::Rawness,
@@ -131,28 +131,28 @@ pub fn unsafe_operations(
     visitor.walk_expr(current);
 }
 
-struct UnsafeVisitor<'a> {
-    db: &'a dyn HirDatabase,
-    infer: &'a InferenceResult,
-    body: &'a Body,
-    resolver: Resolver,
+struct UnsafeVisitor<'db> {
+    db: &'db dyn HirDatabase,
+    infer: &'db InferenceResult,
+    body: &'db Body,
+    resolver: Resolver<'db>,
     def: DefWithBodyId,
     inside_unsafe_block: InsideUnsafeBlock,
     inside_assignment: bool,
     inside_union_destructure: bool,
-    callback: &'a mut dyn FnMut(UnsafeDiagnostic),
+    callback: &'db mut dyn FnMut(UnsafeDiagnostic),
     def_target_features: TargetFeatures,
     // FIXME: This needs to be the edition of the span of each call.
     edition: Edition,
 }
 
-impl<'a> UnsafeVisitor<'a> {
+impl<'db> UnsafeVisitor<'db> {
     fn new(
-        db: &'a dyn HirDatabase,
-        infer: &'a InferenceResult,
-        body: &'a Body,
+        db: &'db dyn HirDatabase,
+        infer: &'db InferenceResult,
+        body: &'db Body,
         def: DefWithBodyId,
-        unsafe_expr_cb: &'a mut dyn FnMut(UnsafeDiagnostic),
+        unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic),
     ) -> Self {
         let resolver = def.resolver(db);
         let def_target_features = match def {
@@ -199,6 +199,17 @@ impl<'a> UnsafeVisitor<'a> {
         }
     }
 
+    fn with_inside_unsafe_block<R>(
+        &mut self,
+        inside_unsafe_block: InsideUnsafeBlock,
+        f: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        let old = mem::replace(&mut self.inside_unsafe_block, inside_unsafe_block);
+        let result = f(self);
+        self.inside_unsafe_block = old;
+        result
+    }
+
     fn walk_pats_top(&mut self, pats: impl Iterator<Item = PatId>, parent_expr: ExprId) {
         let guard = self.resolver.update_to_inner_scope(self.db, self.def, parent_expr);
         pats.for_each(|pat| self.walk_pat(pat));
@@ -303,7 +314,29 @@ impl<'a> UnsafeVisitor<'a> {
                 self.walk_pats_top(std::iter::once(target), current);
                 self.inside_assignment = old_inside_assignment;
             }
-            Expr::InlineAsm(_) => self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm),
+            Expr::InlineAsm(asm) => {
+                self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
+                asm.operands.iter().for_each(|(_, op)| match op {
+                    AsmOperand::In { expr, .. }
+                    | AsmOperand::Out { expr: Some(expr), .. }
+                    | AsmOperand::InOut { expr, .. }
+                    | AsmOperand::Const(expr) => self.walk_expr(*expr),
+                    AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                        self.walk_expr(*in_expr);
+                        if let Some(out_expr) = out_expr {
+                            self.walk_expr(*out_expr);
+                        }
+                    }
+                    AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
+                    AsmOperand::Label(expr) => {
+                        // Inline asm labels are considered safe even when inside unsafe blocks.
+                        self.with_inside_unsafe_block(InsideUnsafeBlock::No, |this| {
+                            this.walk_expr(*expr)
+                        });
+                    }
+                });
+                return;
+            }
             // rustc allows union assignment to propagate through field accesses and casts.
             Expr::Cast { .. } => self.inside_assignment = inside_assignment,
             Expr::Field { .. } => {
@@ -317,17 +350,16 @@ impl<'a> UnsafeVisitor<'a> {
                 }
             }
             Expr::Unsafe { statements, .. } => {
-                let old_inside_unsafe_block =
-                    mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
-                self.walk_pats_top(
-                    statements.iter().filter_map(|statement| match statement {
-                        &Statement::Let { pat, .. } => Some(pat),
-                        _ => None,
-                    }),
-                    current,
-                );
-                self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
-                self.inside_unsafe_block = old_inside_unsafe_block;
+                self.with_inside_unsafe_block(InsideUnsafeBlock::Yes, |this| {
+                    this.walk_pats_top(
+                        statements.iter().filter_map(|statement| match statement {
+                            &Statement::Let { pat, .. } => Some(pat),
+                            _ => None,
+                        }),
+                        current,
+                    );
+                    this.body.walk_child_exprs_without_pats(current, |child| this.walk_expr(child));
+                });
                 return;
             }
             Expr::Block { statements, .. } | Expr::Async { statements, .. } => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 106b996b13e..ed8d8dc2624 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -9,8 +9,8 @@ use chalk_ir::{
 };
 use chalk_solve::rust_ir::InlineBound;
 use hir_def::{
-    AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId,
-    lang_item::LangItem, signatures::TraitFlags,
+    AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
+    TypeAliasId, lang_item::LangItem, signatures::TraitFlags,
 };
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
@@ -343,7 +343,7 @@ where
             })
         }
         AssocItemId::TypeAliasId(it) => {
-            let def_map = db.crate_def_map(trait_.krate(db));
+            let def_map = CrateRootModuleId::from(trait_.krate(db)).def_map(db);
             if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) {
                 ControlFlow::Continue(())
             } else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index f0ec31db8bb..e698fb201cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -594,16 +594,16 @@ impl Index<BindingId> for InferenceResult {
 
 /// The inference context contains all information needed during type inference.
 #[derive(Clone, Debug)]
-pub(crate) struct InferenceContext<'a> {
-    pub(crate) db: &'a dyn HirDatabase,
+pub(crate) struct InferenceContext<'db> {
+    pub(crate) db: &'db dyn HirDatabase,
     pub(crate) owner: DefWithBodyId,
-    pub(crate) body: &'a Body,
+    pub(crate) body: &'db Body,
     /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
     /// and resolve the path via its methods. This will ensure proper error reporting.
-    pub(crate) resolver: Resolver,
+    pub(crate) resolver: Resolver<'db>,
     generic_def: GenericDefId,
     generics: OnceCell<Generics>,
-    table: unify::InferenceTable<'a>,
+    table: unify::InferenceTable<'db>,
     /// The traits in scope, disregarding block modules. This is used for caching purposes.
     traits_in_scope: FxHashSet<TraitId>,
     pub(crate) result: InferenceResult,
@@ -695,12 +695,12 @@ enum ImplTraitReplacingMode {
     TypeAlias,
 }
 
-impl<'a> InferenceContext<'a> {
+impl<'db> InferenceContext<'db> {
     fn new(
-        db: &'a dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         owner: DefWithBodyId,
-        body: &'a Body,
-        resolver: Resolver,
+        body: &'db Body,
+        resolver: Resolver<'db>,
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
         InferenceContext {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
index e3c4f5562d5..003364d4336 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -61,7 +61,7 @@ impl<'a> InferenceTyLoweringContext<'a> {
     #[inline]
     pub(super) fn new(
         db: &'a dyn HirDatabase,
-        resolver: &'a Resolver,
+        resolver: &'a Resolver<'_>,
         store: &'a ExpressionStore,
         diagnostics: &'a Diagnostics,
         source: InferenceTyDiagnosticSource,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 8084b394d04..87b7f3406ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -959,8 +959,8 @@ impl InferenceContext<'_> {
             }
             Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
             Expr::InlineAsm(asm) => {
-                let mut check_expr_asm_operand = |expr, is_input: bool| {
-                    let ty = self.infer_expr_no_expect(expr, ExprIsRead::Yes);
+                let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| {
+                    let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes);
 
                     // If this is an input value, we require its type to be fully resolved
                     // at this point. This allows us to provide helpful coercions which help
@@ -970,18 +970,18 @@ impl InferenceContext<'_> {
                     // allows them to be inferred based on how they are used later in the
                     // function.
                     if is_input {
-                        let ty = self.resolve_ty_shallow(&ty);
+                        let ty = this.resolve_ty_shallow(&ty);
                         match ty.kind(Interner) {
                             TyKind::FnDef(def, parameters) => {
                                 let fnptr_ty = TyKind::Function(
-                                    CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(),
+                                    CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(),
                                 )
                                 .intern(Interner);
-                                _ = self.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
+                                _ = this.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
                             }
                             TyKind::Ref(mutbl, _, base_ty) => {
                                 let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner);
-                                _ = self.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
+                                _ = this.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
                             }
                             _ => {}
                         }
@@ -990,22 +990,28 @@ impl InferenceContext<'_> {
 
                 let diverge = asm.options.contains(AsmOptions::NORETURN);
                 asm.operands.iter().for_each(|(_, operand)| match *operand {
-                    AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true),
+                    AsmOperand::In { expr, .. } => check_expr_asm_operand(self, expr, true),
                     AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => {
-                        check_expr_asm_operand(expr, false)
+                        check_expr_asm_operand(self, expr, false)
                     }
                     AsmOperand::Out { expr: None, .. } => (),
                     AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                        check_expr_asm_operand(in_expr, true);
+                        check_expr_asm_operand(self, in_expr, true);
                         if let Some(out_expr) = out_expr {
-                            check_expr_asm_operand(out_expr, false);
+                            check_expr_asm_operand(self, out_expr, false);
                         }
                     }
-                    // FIXME
-                    AsmOperand::Label(_) => (),
-                    // FIXME
-                    AsmOperand::Const(_) => (),
-                    // FIXME
+                    AsmOperand::Label(expr) => {
+                        self.infer_expr(
+                            expr,
+                            &Expectation::HasType(self.result.standard_types.unit.clone()),
+                            ExprIsRead::No,
+                        );
+                    }
+                    AsmOperand::Const(expr) => {
+                        self.infer_expr(expr, &Expectation::None, ExprIsRead::No);
+                    }
+                    // FIXME: `sym` should report for things that are not functions or statics.
                     AsmOperand::Sym(_) => (),
                 });
                 if diverge {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 9def39d5f97..ea8e7cc2be9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -42,7 +42,6 @@ use hir_def::{
 use hir_expand::name::Name;
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::Captures;
 use stdx::{impl_from, never};
 use triomphe::{Arc, ThinArc};
 
@@ -151,10 +150,10 @@ impl LifetimeElisionKind {
 }
 
 #[derive(Debug)]
-pub struct TyLoweringContext<'a> {
-    pub db: &'a dyn HirDatabase,
-    resolver: &'a Resolver,
-    store: &'a ExpressionStore,
+pub struct TyLoweringContext<'db> {
+    pub db: &'db dyn HirDatabase,
+    resolver: &'db Resolver<'db>,
+    store: &'db ExpressionStore,
     def: GenericDefId,
     generics: OnceCell<Generics>,
     in_binders: DebruijnIndex,
@@ -170,11 +169,11 @@ pub struct TyLoweringContext<'a> {
     lifetime_elision: LifetimeElisionKind,
 }
 
-impl<'a> TyLoweringContext<'a> {
+impl<'db> TyLoweringContext<'db> {
     pub fn new(
-        db: &'a dyn HirDatabase,
-        resolver: &'a Resolver,
-        store: &'a ExpressionStore,
+        db: &'db dyn HirDatabase,
+        resolver: &'db Resolver<'db>,
+        store: &'db ExpressionStore,
         def: GenericDefId,
         lifetime_elision: LifetimeElisionKind,
     ) -> Self {
@@ -1176,13 +1175,13 @@ where
 
 /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
 /// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'a, 'subst: 'a>(
-    db: &dyn HirDatabase,
+fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
+    db: &'db dyn HirDatabase,
     def: GenericDefId,
     explicitly_unsized_tys: &'a FxHashSet<Ty>,
     substitution: &'subst Substitution,
-    resolver: &Resolver,
-) -> Option<impl Iterator<Item = WhereClause> + Captures<'a> + Captures<'subst>> {
+    resolver: &Resolver<'db>,
+) -> Option<impl Iterator<Item = WhereClause>> {
     let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
 
     let trait_self_idx = trait_self_param_idx(db, def);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 8e549ca0cbd..3b295d41e6e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -10,7 +10,7 @@ use chalk_ir::{UniverseIndex, WithKind, cast::Cast};
 use hir_def::{
     AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
     ModuleId, TraitId,
-    nameres::{DefMap, assoc::ImplItems},
+    nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
     signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
 };
 use hir_expand::name::Name;
@@ -152,7 +152,7 @@ impl TraitImpls {
         let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered();
         let mut impls = FxHashMap::default();
 
-        Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
+        Self::collect_def_map(db, &mut impls, crate_def_map(db, krate));
 
         Arc::new(Self::finish(impls))
     }
@@ -164,7 +164,7 @@ impl TraitImpls {
         let _p = tracing::info_span!("trait_impls_in_block_query").entered();
         let mut impls = FxHashMap::default();
 
-        Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
+        Self::collect_def_map(db, &mut impls, block_def_map(db, block));
 
         if impls.is_empty() { None } else { Some(Arc::new(Self::finish(impls))) }
     }
@@ -214,7 +214,7 @@ impl TraitImpls {
             for konst in module_data.scope.unnamed_consts() {
                 let body = db.body(konst.into());
                 for (_, block_def_map) in body.blocks(db) {
-                    Self::collect_def_map(db, map, &block_def_map);
+                    Self::collect_def_map(db, map, block_def_map);
                 }
             }
         }
@@ -280,8 +280,8 @@ impl InherentImpls {
         let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
         let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
 
-        let crate_def_map = db.crate_def_map(krate);
-        impls.collect_def_map(db, &crate_def_map);
+        let crate_def_map = crate_def_map(db, krate);
+        impls.collect_def_map(db, crate_def_map);
         impls.shrink_to_fit();
 
         Arc::new(impls)
@@ -294,8 +294,8 @@ impl InherentImpls {
         let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
         let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
 
-        let block_def_map = db.block_def_map(block);
-        impls.collect_def_map(db, &block_def_map);
+        let block_def_map = block_def_map(db, block);
+        impls.collect_def_map(db, block_def_map);
         impls.shrink_to_fit();
 
         if impls.map.is_empty() && impls.invalid_impls.is_empty() {
@@ -337,7 +337,7 @@ impl InherentImpls {
             for konst in module_data.scope.unnamed_consts() {
                 let body = db.body(konst.into());
                 for (_, block_def_map) in body.blocks(db) {
-                    self.collect_def_map(db, &block_def_map);
+                    self.collect_def_map(db, block_def_map);
                 }
             }
         }
@@ -1399,7 +1399,7 @@ fn iterate_inherent_methods(
             )?;
         }
 
-        block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
+        block = block_def_map(db, block_id).parent().and_then(|module| module.containing_block());
     }
 
     for krate in def_crates {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 26ef95d264b..7cf948b178e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -5,6 +5,7 @@ use std::cmp::{self, Ordering};
 
 use chalk_ir::TyKind;
 use hir_def::{
+    CrateRootModuleId,
     builtin_type::{BuiltinInt, BuiltinUint},
     resolver::HasResolver,
 };
@@ -153,7 +154,7 @@ impl Evaluator<'_> {
     ) -> Result<Option<FunctionId>> {
         // `PanicFmt` is redirected to `ConstPanicFmt`
         if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) {
-            let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db);
+            let resolver = CrateRootModuleId::from(self.crate_id).resolver(self.db);
 
             let Some(const_panic_fmt) =
                 LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 7b48b15d9ea..7fcc89e5183 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -68,16 +68,16 @@ struct DropScope {
     locals: Vec<LocalId>,
 }
 
-struct MirLowerCtx<'a> {
+struct MirLowerCtx<'db> {
     result: MirBody,
     owner: DefWithBodyId,
     current_loop_blocks: Option<LoopBlocks>,
     labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
     discr_temp: Option<Place>,
-    db: &'a dyn HirDatabase,
-    body: &'a Body,
-    infer: &'a InferenceResult,
-    resolver: Resolver,
+    db: &'db dyn HirDatabase,
+    body: &'db Body,
+    infer: &'db InferenceResult,
+    resolver: Resolver<'db>,
     drop_scopes: Vec<DropScope>,
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index bcd8aa6c4e9..8f0d17c9dc4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -7,7 +7,7 @@ use base_db::{
     SourceRoot, SourceRootId, SourceRootInput,
 };
 
-use hir_def::{ModuleId, db::DefDatabase};
+use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
 use hir_expand::EditionedFileId;
 use rustc_hash::FxHashMap;
 use salsa::{AsDynDatabase, Durability};
@@ -118,7 +118,7 @@ impl TestDB {
     pub(crate) fn module_for_file_opt(&self, file_id: impl Into<FileId>) -> Option<ModuleId> {
         let file_id = file_id.into();
         for &krate in self.relevant_crates(file_id).iter() {
-            let crate_def_map = self.crate_def_map(krate);
+            let crate_def_map = crate_def_map(self, krate);
             for (local_id, data) in crate_def_map.modules() {
                 if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
                     return Some(crate_def_map.module_id(local_id));
@@ -137,7 +137,7 @@ impl TestDB {
     ) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
         let mut files = Vec::new();
         for &krate in self.all_crates().iter() {
-            let crate_def_map = self.crate_def_map(krate);
+            let crate_def_map = crate_def_map(self, krate);
             for (module_id, _) in crate_def_map.modules() {
                 let file_id = crate_def_map[module_id].origin.file_id();
                 files.extend(file_id)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index cc37f65c26c..2b75bd6f160 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -132,7 +132,7 @@ fn check_impl(
             None => continue,
         };
         let def_map = module.def_map(&db);
-        visit_module(&db, &def_map, module.local_id, &mut |it| {
+        visit_module(&db, def_map, module.local_id, &mut |it| {
             let def = match it {
                 ModuleDefId::FunctionId(it) => it.into(),
                 ModuleDefId::EnumVariantId(it) => it.into(),
@@ -391,7 +391,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
     let def_map = module.def_map(&db);
 
     let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
-    visit_module(&db, &def_map, module.local_id, &mut |it| {
+    visit_module(&db, def_map, module.local_id, &mut |it| {
         let def = match it {
             ModuleDefId::FunctionId(it) => it.into(),
             ModuleDefId::EnumVariantId(it) => it.into(),
@@ -504,7 +504,7 @@ pub(crate) fn visit_module(
     fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(ModuleDefId)) {
         for (_, def_map) in body.blocks(db) {
             for (mod_id, _) in def_map.modules() {
-                visit_module(db, &def_map, mod_id, cb);
+                visit_module(db, def_map, mod_id, cb);
             }
         }
     }
@@ -570,7 +570,7 @@ fn salsa_bug() {
 
     let module = db.module_for_file(pos.file_id.file_id(&db));
     let crate_def_map = module.def_map(&db);
-    visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+    visit_module(&db, crate_def_map, module.local_id, &mut |def| {
         db.infer(match def {
             ModuleDefId::FunctionId(it) => it.into(),
             ModuleDefId::EnumVariantId(it) => it.into(),
@@ -609,7 +609,7 @@ fn salsa_bug() {
 
     let module = db.module_for_file(pos.file_id.file_id(&db));
     let crate_def_map = module.def_map(&db);
-    visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+    visit_module(&db, crate_def_map, module.local_id, &mut |def| {
         db.infer(match def {
             ModuleDefId::FunctionId(it) => it.into(),
             ModuleDefId::EnumVariantId(it) => it.into(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
index 73f1ae56457..88d21be81ea 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
@@ -20,7 +20,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
     let def_map = module.def_map(&db);
 
     let mut defs = Vec::new();
-    visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
+    visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it));
 
     let mut captures_info = Vec::new();
     for def in defs {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index 0542be0ba89..48474d2d26d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -19,7 +19,7 @@ fn foo() -> i32 {
         let events = db.log_executed(|| {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
-            visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+            visit_module(&db, crate_def_map, module.local_id, &mut |def| {
                 if let ModuleDefId::FunctionId(it) = def {
                     db.infer(it.into());
                 }
@@ -41,7 +41,7 @@ fn foo() -> i32 {
         let events = db.log_executed(|| {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
-            visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+            visit_module(&db, crate_def_map, module.local_id, &mut |def| {
                 if let ModuleDefId::FunctionId(it) = def {
                     db.infer(it.into());
                 }
@@ -70,7 +70,7 @@ fn baz() -> i32 {
         let events = db.log_executed(|| {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
-            visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+            visit_module(&db, crate_def_map, module.local_id, &mut |def| {
                 if let ModuleDefId::FunctionId(it) = def {
                     db.infer(it.into());
                 }
@@ -97,7 +97,7 @@ fn baz() -> i32 {
         let events = db.log_executed(|| {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
-            visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+            visit_module(&db, crate_def_map, module.local_id, &mut |def| {
                 if let ModuleDefId::FunctionId(it) = def {
                     db.infer(it.into());
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index 446f0b21a2a..ea7a113cae3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -1505,6 +1505,10 @@ fn main() {
             !119..120 'o': i32
             293..294 'o': i32
             308..317 'thread_id': usize
+            !314..320 'OffPtr': usize
+            !333..338 'OffFn': usize
+            !354..355 '0': i32
+            !371..382 'MEM_RELEASE': usize
         "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index eeebe38f182..cf51671afb2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3902,3 +3902,66 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn regression_19734() {
+    check_infer(
+        r#"
+trait Foo {
+    type Gat<'o>;
+}
+
+trait Bar {
+    fn baz() -> <Self::Xyz as Foo::Gat<'_>>;
+}
+
+fn foo<T: Bar>() {
+    T::baz();
+}
+    "#,
+        expect![[r#"
+            110..127 '{     ...z(); }': ()
+            116..122 'T::baz': fn baz<T>() -> <{unknown} as Foo>::Gat<'?>
+            116..124 'T::baz()': Foo::Gat<'?, {unknown}>
+        "#]],
+    );
+}
+
+#[test]
+fn asm_const_label() {
+    check_infer(
+        r#"
+//- minicore: asm
+const fn bar() -> i32 { 123 }
+fn baz(s: &str) {}
+
+fn foo() {
+    unsafe {
+        core::arch::asm!(
+            "mov eax, {}",
+            "jmp {}",
+            const bar(),
+            label {
+                baz("hello");
+            },
+        );
+    }
+}
+    "#,
+        expect![[r#"
+            22..29 '{ 123 }': i32
+            24..27 '123': i32
+            37..38 's': &'? str
+            46..48 '{}': ()
+            !0..68 'builti...");},)': ()
+            !40..43 'bar': fn bar() -> i32
+            !40..45 'bar()': i32
+            !51..66 '{baz("hello");}': ()
+            !52..55 'baz': fn baz(&'? str)
+            !52..64 'baz("hello")': ()
+            !56..63 '"hello"': &'static str
+            59..257 '{     ...   } }': ()
+            65..255 'unsafe...     }': ()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 14137605c9f..2b527a4ae12 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4884,3 +4884,22 @@ async fn baz<T: AsyncFnOnce(u32) -> i32>(c: T) {
         "#]],
     );
 }
+
+#[test]
+fn import_trait_items() {
+    check_infer(
+        r#"
+//- minicore: default
+use core::default::Default::default;
+fn main() {
+    let a: i32 = default();
+}
+    "#,
+        expect![[r#"
+            47..78 '{     ...t(); }': ()
+            57..58 'a': i32
+            66..73 'default': {unknown}
+            66..75 'default()': i32
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 6e1cd9a310f..d6b43aeed4d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -984,7 +984,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
         let mut defs: Vec<GenericDefId> = Vec::new();
         let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap();
         let def_map = module.def_map(&db);
-        crate::tests::visit_module(&db, &def_map, module.local_id, &mut |it| {
+        crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| {
             defs.push(match it {
                 ModuleDefId::FunctionId(it) => it.into(),
                 ModuleDefId::AdtId(it) => it.into(),
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index b1c478d1bf4..b1cf30b98f5 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -105,11 +105,12 @@ impl HasAttrs for crate::Crate {
 /// Resolves the item `link` points to in the scope of `def`.
 pub fn resolve_doc_path_on(
     db: &dyn HirDatabase,
-    def: impl HasAttrs,
+    def: impl HasAttrs + Copy,
     link: &str,
     ns: Option<Namespace>,
+    is_inner_doc: bool,
 ) -> Option<DocLinkDef> {
-    resolve_doc_path_on_(db, link, def.attr_id(), ns)
+    resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner_doc)
 }
 
 fn resolve_doc_path_on_(
@@ -117,9 +118,18 @@ fn resolve_doc_path_on_(
     link: &str,
     attr_id: AttrDefId,
     ns: Option<Namespace>,
+    is_inner_doc: bool,
 ) -> Option<DocLinkDef> {
     let resolver = match attr_id {
-        AttrDefId::ModuleId(it) => it.resolver(db),
+        AttrDefId::ModuleId(it) => {
+            if is_inner_doc {
+                it.resolver(db)
+            } else if let Some(parent) = Module::from(it).parent(db) {
+                parent.id.resolver(db)
+            } else {
+                it.resolver(db)
+            }
+        }
         AttrDefId::FieldId(it) => it.parent.resolver(db),
         AttrDefId::AdtId(it) => it.resolver(db),
         AttrDefId::FunctionId(it) => it.resolver(db),
@@ -160,7 +170,7 @@ fn resolve_doc_path_on_(
 
 fn resolve_assoc_or_field(
     db: &dyn HirDatabase,
-    resolver: Resolver,
+    resolver: Resolver<'_>,
     path: ModPath,
     name: Name,
     ns: Option<Namespace>,
@@ -248,7 +258,7 @@ fn resolve_assoc_item(
 
 fn resolve_impl_trait_item(
     db: &dyn HirDatabase,
-    resolver: Resolver,
+    resolver: Resolver<'_>,
     ty: &Type,
     name: &Name,
     ns: Option<Namespace>,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 3f1d5bb01f2..3a91050d15f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -97,7 +97,8 @@ pub use crate::{
     diagnostics::*,
     has_source::HasSource,
     semantics::{
-        PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits,
+        PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo,
+        VisibleTraits,
     },
 };
 
@@ -119,7 +120,7 @@ pub use {
         find_path::PrefixKind,
         import_map,
         lang_item::LangItem,
-        nameres::{DefMap, ModuleSource},
+        nameres::{DefMap, ModuleSource, crate_def_map},
         per_ns::Namespace,
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
@@ -227,7 +228,7 @@ impl Crate {
     }
 
     pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
-        let def_map = db.crate_def_map(self.id);
+        let def_map = crate_def_map(db, self.id);
         def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
     }
 
@@ -528,7 +529,7 @@ impl Module {
     /// might be missing `krate`. This can happen if a module's file is not included
     /// in the module tree of any target in `Cargo.toml`.
     pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
-        let def_map = db.crate_def_map(self.id.krate());
+        let def_map = crate_def_map(db, self.id.krate());
         Module { id: def_map.crate_root().into() }
     }
 
@@ -2468,7 +2469,7 @@ impl Function {
         {
             return None;
         }
-        let def_map = db.crate_def_map(HasModule::krate(&self.id, db));
+        let def_map = crate_def_map(db, HasModule::krate(&self.id, db));
         def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
     }
 
@@ -4015,8 +4016,7 @@ impl BuiltinAttr {
         if let builtin @ Some(_) = Self::builtin(name) {
             return builtin;
         }
-        let idx = db
-            .crate_def_map(krate.id)
+        let idx = crate_def_map(db, krate.id)
             .registered_attrs()
             .iter()
             .position(|it| it.as_str() == name)? as u32;
@@ -4031,7 +4031,7 @@ impl BuiltinAttr {
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
         match self.krate {
             Some(krate) => Name::new_symbol_root(
-                db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
+                crate_def_map(db, krate).registered_attrs()[self.idx as usize].clone(),
             ),
             None => Name::new_symbol_root(Symbol::intern(
                 hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name,
@@ -4059,14 +4059,14 @@ impl ToolModule {
     pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
         let krate = krate.id;
         let idx =
-            db.crate_def_map(krate).registered_tools().iter().position(|it| it.as_str() == name)?
+            crate_def_map(db, krate).registered_tools().iter().position(|it| it.as_str() == name)?
                 as u32;
         Some(ToolModule { krate, idx })
     }
 
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
         Name::new_symbol_root(
-            db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(),
+            crate_def_map(db, self.krate).registered_tools()[self.idx as usize].clone(),
         )
     }
 
@@ -4488,7 +4488,7 @@ impl Impl {
             MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
                 let module_id = self.id.lookup(db).container;
                 (
-                    db.crate_def_map(module_id.krate())[module_id.local_id]
+                    crate_def_map(db, module_id.krate())[module_id.local_id]
                         .scope
                         .derive_macro_invoc(ast_id, derive_attr_index)?,
                     derive_index,
@@ -4530,7 +4530,7 @@ pub struct TraitRef {
 impl TraitRef {
     pub(crate) fn new_with_resolver(
         db: &dyn HirDatabase,
-        resolver: &Resolver,
+        resolver: &Resolver<'_>,
         trait_ref: hir_ty::TraitRef,
     ) -> TraitRef {
         let env = resolver
@@ -4752,13 +4752,13 @@ pub struct Type {
 }
 
 impl Type {
-    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
+    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type {
         Type::new_with_resolver_inner(db, resolver, ty)
     }
 
     pub(crate) fn new_with_resolver_inner(
         db: &dyn HirDatabase,
-        resolver: &Resolver,
+        resolver: &Resolver<'_>,
         ty: Ty,
     ) -> Type {
         let environment = resolver
@@ -6400,7 +6400,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
                 })
                 .filter_map(|&krate| {
                     let segments = segments.clone();
-                    let mut def_map = db.crate_def_map(krate);
+                    let mut def_map = crate_def_map(db, krate);
                     let mut module = &def_map[DefMap::ROOT];
                     let mut segments = segments.with_position().peekable();
                     while let Some((_, segment)) = segments.next_if(|&(position, _)| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 4d092c1f0bb..caa6700de9f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -15,7 +15,7 @@ use hir_def::{
     DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
     expr_store::{Body, ExprOrPatSource, path::Path},
     hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
-    nameres::ModuleOrigin,
+    nameres::{ModuleOrigin, crate_def_map},
     resolver::{self, HasResolver, Resolver, TypeNs},
     type_ref::Mutability,
 };
@@ -103,6 +103,26 @@ impl PathResolution {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct PathResolutionPerNs {
+    pub type_ns: Option<PathResolution>,
+    pub value_ns: Option<PathResolution>,
+    pub macro_ns: Option<PathResolution>,
+}
+
+impl PathResolutionPerNs {
+    pub fn new(
+        type_ns: Option<PathResolution>,
+        value_ns: Option<PathResolution>,
+        macro_ns: Option<PathResolution>,
+    ) -> Self {
+        PathResolutionPerNs { type_ns, value_ns, macro_ns }
+    }
+    pub fn any(&self) -> Option<PathResolution> {
+        self.type_ns.or(self.value_ns).or(self.macro_ns)
+    }
+}
+
 #[derive(Debug)]
 pub struct TypeInfo {
     /// The original type of the expression or pattern.
@@ -341,7 +361,7 @@ impl<'db> SemanticsImpl<'db> {
         match file_id {
             HirFileId::FileId(file_id) => {
                 let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
-                let def_map = self.db.crate_def_map(module.krate().id);
+                let def_map = crate_def_map(self.db, module.krate().id);
                 match def_map[module.id.local_id].origin {
                     ModuleOrigin::CrateRoot { .. } => None,
                     ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
@@ -1606,6 +1626,10 @@ impl<'db> SemanticsImpl<'db> {
         self.resolve_path_with_subst(path).map(|(it, _)| it)
     }
 
+    pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option<PathResolutionPerNs> {
+        self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path)
+    }
+
     pub fn resolve_path_with_subst(
         &self,
         path: &ast::Path,
@@ -1711,13 +1735,13 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     /// Returns none if the file of the node is not part of a crate.
-    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
         let node = self.find_file(node);
         self.analyze_impl(node, None, true)
     }
 
     /// Returns none if the file of the node is not part of a crate.
-    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
         let node = self.find_file(node);
         self.analyze_impl(node, None, false)
     }
@@ -1726,7 +1750,7 @@ impl<'db> SemanticsImpl<'db> {
         &self,
         node: &SyntaxNode,
         offset: TextSize,
-    ) -> Option<SourceAnalyzer> {
+    ) -> Option<SourceAnalyzer<'db>> {
         let node = self.find_file(node);
         self.analyze_impl(node, Some(offset), false)
     }
@@ -1737,7 +1761,7 @@ impl<'db> SemanticsImpl<'db> {
         offset: Option<TextSize>,
         // replace this, just make the inference result a `LazyCell`
         infer_body: bool,
-    ) -> Option<SourceAnalyzer> {
+    ) -> Option<SourceAnalyzer<'db>> {
         let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
 
         let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@@ -1984,13 +2008,13 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
 /// Note that if you are wondering "what does this specific existing name mean?",
 /// you'd better use the `resolve_` family of methods.
 #[derive(Debug)]
-pub struct SemanticsScope<'a> {
-    pub db: &'a dyn HirDatabase,
+pub struct SemanticsScope<'db> {
+    pub db: &'db dyn HirDatabase,
     file_id: HirFileId,
-    resolver: Resolver,
+    resolver: Resolver<'db>,
 }
 
-impl SemanticsScope<'_> {
+impl<'db> SemanticsScope<'db> {
     pub fn module(&self) -> Module {
         Module { id: self.resolver.module() }
     }
@@ -2006,7 +2030,7 @@ impl SemanticsScope<'_> {
         })
     }
 
-    pub(crate) fn resolver(&self) -> &Resolver {
+    pub(crate) fn resolver(&self) -> &Resolver<'db> {
         &self.resolver
     }
 
@@ -2133,7 +2157,7 @@ impl ops::Deref for VisibleTraits {
 struct RenameConflictsVisitor<'a> {
     db: &'a dyn HirDatabase,
     owner: DefWithBodyId,
-    resolver: Resolver,
+    resolver: Resolver<'a>,
     body: &'a Body,
     to_be_renamed: BindingId,
     new_name: Symbol,
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 587c51d8cc9..172af456d92 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -96,6 +96,7 @@ use hir_def::{
         keys::{self, Key},
     },
     hir::{BindingId, Expr, LabelId},
+    nameres::{block_def_map, crate_def_map},
 };
 use hir_expand::{
     EditionedFileId, ExpansionInfo, HirFileId, InMacroFile, MacroCallId, attrs::AttrId,
@@ -180,7 +181,7 @@ impl SourceToDefCtx<'_, '_> {
 
             for &crate_id in self.db.relevant_crates(file).iter() {
                 // Note: `mod` declarations in block modules cannot be supported here
-                let crate_def_map = self.db.crate_def_map(crate_id);
+                let crate_def_map = crate_def_map(self.db, crate_id);
                 let n_mods = mods.len();
                 let modules = |file| {
                     crate_def_map
@@ -226,7 +227,7 @@ impl SourceToDefCtx<'_, '_> {
         let parent_module = match parent_declaration {
             Some(Either::Right(parent_block)) => self
                 .block_to_def(parent_block.as_ref())
-                .map(|block| self.db.block_def_map(block).root_module_id()),
+                .map(|block| block_def_map(self.db, block).root_module_id()),
             Some(Either::Left(parent_declaration)) => {
                 self.module_to_def(parent_declaration.as_ref())
             }
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index c1a75ce7e57..ea21546f9d7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -10,7 +10,9 @@ use std::iter::{self, once};
 use crate::{
     Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field,
     Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait,
-    TraitAlias, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::PathResolution,
+    TraitAlias, TupleField, Type, TypeAlias, Variant,
+    db::HirDatabase,
+    semantics::{PathResolution, PathResolutionPerNs},
 };
 use either::Either;
 use hir_def::{
@@ -24,7 +26,7 @@ use hir_def::{
     },
     hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
     lang_item::LangItem,
-    nameres::MacroSubNs,
+    nameres::{MacroSubNs, crate_def_map},
     resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope},
     type_ref::{Mutability, TypeRefId},
 };
@@ -57,9 +59,9 @@ use triomphe::Arc;
 /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
 /// original source files. It should not be used inside the HIR itself.
 #[derive(Debug)]
-pub(crate) struct SourceAnalyzer {
+pub(crate) struct SourceAnalyzer<'db> {
     pub(crate) file_id: HirFileId,
-    pub(crate) resolver: Resolver,
+    pub(crate) resolver: Resolver<'db>,
     pub(crate) body_or_sig: Option<BodyOrSig>,
 }
 
@@ -85,32 +87,32 @@ pub(crate) enum BodyOrSig {
     },
 }
 
-impl SourceAnalyzer {
+impl<'db> SourceAnalyzer<'db> {
     pub(crate) fn new_for_body(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: DefWithBodyId,
         node: InFile<&SyntaxNode>,
         offset: Option<TextSize>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
     }
 
     pub(crate) fn new_for_body_no_infer(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: DefWithBodyId,
         node: InFile<&SyntaxNode>,
         offset: Option<TextSize>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         Self::new_for_body_(db, def, node, offset, None)
     }
 
     pub(crate) fn new_for_body_(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: DefWithBodyId,
         node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
         offset: Option<TextSize>,
         infer: Option<Arc<InferenceResult>>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         let (body, source_map) = db.body_with_source_map(def);
         let scopes = db.expr_scopes(def);
         let scope = match offset {
@@ -134,11 +136,11 @@ impl SourceAnalyzer {
     }
 
     pub(crate) fn new_generic_def(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: GenericDefId,
         InFile { file_id, .. }: InFile<&SyntaxNode>,
         _offset: Option<TextSize>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def);
         let resolver = def.resolver(db);
         SourceAnalyzer {
@@ -149,11 +151,11 @@ impl SourceAnalyzer {
     }
 
     pub(crate) fn new_variant_body(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: VariantId,
         InFile { file_id, .. }: InFile<&SyntaxNode>,
         _offset: Option<TextSize>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         let (fields, source_map) = db.variant_fields_with_source_map(def);
         let resolver = def.resolver(db);
         SourceAnalyzer {
@@ -168,9 +170,9 @@ impl SourceAnalyzer {
     }
 
     pub(crate) fn new_for_resolver(
-        resolver: Resolver,
+        resolver: Resolver<'db>,
         node: InFile<&SyntaxNode>,
-    ) -> SourceAnalyzer {
+    ) -> SourceAnalyzer<'db> {
         SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id }
     }
 
@@ -220,7 +222,7 @@ impl SourceAnalyzer {
         self.store_sm()?.expansion(node)
     }
 
-    fn trait_environment(&self, db: &dyn HirDatabase) -> Arc<TraitEnvironment> {
+    fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
         self.body_().map(|(def, ..)| def).map_or_else(
             || TraitEnvironment::empty(self.resolver.krate()),
             |def| db.trait_environment_for_body(def),
@@ -259,7 +261,7 @@ impl SourceAnalyzer {
         infer.expr_adjustments.get(&expr_id).map(|v| &**v)
     }
 
-    pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
+    pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
         let type_ref = self.type_id(ty)?;
         let ty = TyLoweringContext::new(
             db,
@@ -277,7 +279,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn type_of_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         expr: &ast::Expr,
     ) -> Option<(Type, Option<Type>)> {
         let expr_id = self.expr_id(expr.clone())?;
@@ -293,7 +295,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn type_of_pat(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         pat: &ast::Pat,
     ) -> Option<(Type, Option<Type>)> {
         let expr_or_pat_id = self.pat_id(pat)?;
@@ -316,7 +318,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn type_of_binding_in_pat(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         pat: &ast::IdentPat,
     ) -> Option<Type> {
         let binding_id = self.binding_id_of_pat(pat)?;
@@ -328,7 +330,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn type_of_self(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         _param: &ast::SelfParam,
     ) -> Option<Type> {
         let binding = self.body()?.self_param?;
@@ -338,7 +340,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn binding_mode_of_pat(
         &self,
-        _db: &dyn HirDatabase,
+        _db: &'db dyn HirDatabase,
         pat: &ast::IdentPat,
     ) -> Option<BindingMode> {
         let id = self.pat_id(&pat.clone().into())?;
@@ -353,7 +355,7 @@ impl SourceAnalyzer {
     }
     pub(crate) fn pattern_adjustments(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         pat: &ast::Pat,
     ) -> Option<SmallVec<[Type; 1]>> {
         let pat_id = self.pat_id(pat)?;
@@ -370,7 +372,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_method_call_as_callable(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<Callable> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -384,7 +386,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_method_call(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<Function> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -395,7 +397,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_method_call_fallback(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -419,7 +421,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_expr_as_callable(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         call: &ast::Expr,
     ) -> Option<Callable> {
         let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
@@ -441,7 +443,7 @@ impl SourceAnalyzer {
         &self,
         field_expr: ExprId,
         infer: &InferenceResult,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
     ) -> Option<GenericSubstitution> {
         let body = self.store()?;
         if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
@@ -457,7 +459,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_field_fallback(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         field: &ast::FieldExpr,
     ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
         let (def, ..) = self.body_()?;
@@ -490,7 +492,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_range_pat(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         range_pat: &ast::RangePat,
     ) -> Option<StructId> {
         let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
@@ -509,7 +511,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_range_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         range_expr: &ast::RangeExpr,
     ) -> Option<StructId> {
         let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
@@ -529,7 +531,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_await_to_poll(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         await_expr: &ast::AwaitExpr,
     ) -> Option<FunctionId> {
         let mut ty = self.ty_of_expr(await_expr.expr()?)?.clone();
@@ -566,7 +568,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_prefix_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         prefix_expr: &ast::PrefixExpr,
     ) -> Option<FunctionId> {
         let (op_trait, op_fn) = match prefix_expr.op_kind()? {
@@ -608,7 +610,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_index_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         index_expr: &ast::IndexExpr,
     ) -> Option<FunctionId> {
         let base_ty = self.ty_of_expr(index_expr.base()?)?;
@@ -640,7 +642,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_bin_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         binop_expr: &ast::BinExpr,
     ) -> Option<FunctionId> {
         let op = binop_expr.op_kind()?;
@@ -661,7 +663,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_try_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         try_expr: &ast::TryExpr,
     ) -> Option<FunctionId> {
         let ty = self.ty_of_expr(try_expr.expr()?)?;
@@ -680,7 +682,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_record_field(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         field: &ast::RecordExprField,
     ) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
         let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
@@ -724,7 +726,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_record_pat_field(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         field: &ast::RecordPatField,
     ) -> Option<(Field, Type, GenericSubstitution)> {
         let field_name = field.field_name()?.as_name();
@@ -745,14 +747,14 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_macro_call(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<Macro> {
         let bs = self.store_sm()?;
         bs.expansion(macro_call).and_then(|it| {
             // FIXME: Block def maps
             let def = it.lookup(db).def;
-            db.crate_def_map(def.krate)
+            crate_def_map(db, def.krate)
                 .macro_def_to_macro_id
                 .get(&def.kind.erased_ast_id())
                 .map(|it| (*it).into())
@@ -761,7 +763,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_bind_pat_to_const(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         pat: &ast::IdentPat,
     ) -> Option<ModuleDef> {
         let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
@@ -795,7 +797,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_offset_of_field(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         name_ref: &ast::NameRef,
     ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> {
         let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
@@ -867,7 +869,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_path(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         path: &ast::Path,
     ) -> Option<(PathResolution, Option<GenericSubstitution>)> {
         let parent = path.syntax().parent();
@@ -1159,7 +1161,9 @@ impl SourceAnalyzer {
                 prefer_value_ns,
                 name_hygiene(db, InFile::new(self.file_id, path.syntax())),
                 Some(&store),
-            )?;
+                false,
+            )
+            .any()?;
             let subst = (|| {
                 let parent = parent()?;
                 let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {
@@ -1209,9 +1213,29 @@ impl SourceAnalyzer {
         }
     }
 
-    pub(crate) fn record_literal_missing_fields(
+    pub(crate) fn resolve_hir_path_per_ns(
         &self,
         db: &dyn HirDatabase,
+        path: &ast::Path,
+    ) -> Option<PathResolutionPerNs> {
+        let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
+        let hir_path =
+            collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
+        let store = collector.store.finish();
+        Some(resolve_hir_path_(
+            db,
+            &self.resolver,
+            &hir_path,
+            false,
+            name_hygiene(db, InFile::new(self.file_id, path.syntax())),
+            Some(&store),
+            true,
+        ))
+    }
+
+    pub(crate) fn record_literal_missing_fields(
+        &self,
+        db: &'db dyn HirDatabase,
         literal: &ast::RecordExpr,
     ) -> Option<Vec<(Field, Type)>> {
         let body = self.store()?;
@@ -1234,7 +1258,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn record_pattern_missing_fields(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         pattern: &ast::RecordPat,
     ) -> Option<Vec<(Field, Type)>> {
         let body = self.store()?;
@@ -1251,7 +1275,7 @@ impl SourceAnalyzer {
 
     fn missing_fields(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         substs: &Substitution,
         variant: VariantId,
         missing_fields: Vec<LocalFieldId>,
@@ -1270,7 +1294,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn expand(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<MacroCallId> {
         self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| {
@@ -1288,7 +1312,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn is_unsafe_macro_call_expr(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         macro_expr: InFile<&ast::MacroExpr>,
     ) -> bool {
         if let Some((def, body, sm, Some(infer))) = self.body_() {
@@ -1313,7 +1337,7 @@ impl SourceAnalyzer {
 
     pub(crate) fn resolve_offset_in_format_args(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         format_args: InFile<&ast::FormatArgsExpr>,
         offset: TextSize,
     ) -> Option<(TextRange, Option<PathResolution>)> {
@@ -1384,7 +1408,7 @@ impl SourceAnalyzer {
 
     fn resolve_impl_method_or_trait_def(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         func: FunctionId,
         substs: Substitution,
     ) -> FunctionId {
@@ -1393,7 +1417,7 @@ impl SourceAnalyzer {
 
     fn resolve_impl_method_or_trait_def_with_subst(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         func: FunctionId,
         substs: Substitution,
     ) -> (FunctionId, Substitution) {
@@ -1407,7 +1431,7 @@ impl SourceAnalyzer {
 
     fn resolve_impl_const_or_trait_def_with_subst(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         const_id: ConstId,
         subs: Substitution,
     ) -> (ConstId, Substitution) {
@@ -1421,7 +1445,7 @@ impl SourceAnalyzer {
 
     fn lang_trait_fn(
         &self,
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         lang_trait: LangItem,
         method_name: &Name,
     ) -> Option<(TraitId, FunctionId)> {
@@ -1527,18 +1551,18 @@ fn adjust(
 #[inline]
 pub(crate) fn resolve_hir_path(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     path: &Path,
     hygiene: HygieneId,
     store: Option<&ExpressionStore>,
 ) -> Option<PathResolution> {
-    resolve_hir_path_(db, resolver, path, false, hygiene, store)
+    resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any()
 }
 
 #[inline]
 pub(crate) fn resolve_hir_path_as_attr_macro(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     path: &Path,
 ) -> Option<Macro> {
     resolver
@@ -1549,12 +1573,13 @@ pub(crate) fn resolve_hir_path_as_attr_macro(
 
 fn resolve_hir_path_(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     path: &Path,
     prefer_value_ns: bool,
     hygiene: HygieneId,
     store: Option<&ExpressionStore>,
-) -> Option<PathResolution> {
+    resolve_per_ns: bool,
+) -> PathResolutionPerNs {
     let types = || {
         let (ty, unresolved) = match path.type_anchor() {
             Some(type_ref) => resolver.generic_def().and_then(|def| {
@@ -1635,14 +1660,36 @@ fn resolve_hir_path_(
             .map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into())))
     };
 
-    if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
-        .or_else(items)
-        .or_else(macros)
+    if resolve_per_ns {
+        PathResolutionPerNs {
+            type_ns: types().or_else(items),
+            value_ns: values(),
+            macro_ns: macros(),
+        }
+    } else {
+        let res = if prefer_value_ns {
+            values()
+                .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None))
+                .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None))
+        } else {
+            types()
+                .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None))
+                .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None))
+        };
+
+        if res.any().is_some() {
+            res
+        } else if let Some(type_ns) = items() {
+            PathResolutionPerNs::new(Some(type_ns), None, None)
+        } else {
+            PathResolutionPerNs::new(None, None, macros())
+        }
+    }
 }
 
 fn resolve_hir_value_path(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     body_owner: Option<DefWithBodyId>,
     path: &Path,
     hygiene: HygieneId,
@@ -1680,7 +1727,7 @@ fn resolve_hir_value_path(
 /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
 fn resolve_hir_path_qualifier(
     db: &dyn HirDatabase,
-    resolver: &Resolver,
+    resolver: &Resolver<'_>,
     path: &Path,
     store: &ExpressionStore,
 ) -> Option<PathResolution> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
index 7e8735bd7a2..a9df6f6fc36 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
@@ -1,3 +1,4 @@
+use either::Either;
 use syntax::{
     ast::{
         self, AstNode, HasName, HasTypeBounds,
@@ -30,10 +31,11 @@ pub(crate) fn move_bounds_to_where_clause(
 ) -> Option<()> {
     let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
 
-    let mut type_params = type_param_list.type_or_const_params();
+    let mut type_params = type_param_list.generic_params();
     if type_params.all(|p| match p {
-        ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(),
-        ast::TypeOrConstParam::Const(_) => true,
+        ast::GenericParam::TypeParam(t) => t.type_bound_list().is_none(),
+        ast::GenericParam::LifetimeParam(l) => l.type_bound_list().is_none(),
+        ast::GenericParam::ConstParam(_) => true,
     }) {
         return None;
     }
@@ -53,20 +55,23 @@ pub(crate) fn move_bounds_to_where_clause(
                 match parent {
                     ast::Fn(it) => it.get_or_create_where_clause(),
                     ast::Trait(it) => it.get_or_create_where_clause(),
+                    ast::TraitAlias(it) => it.get_or_create_where_clause(),
                     ast::Impl(it) => it.get_or_create_where_clause(),
                     ast::Enum(it) => it.get_or_create_where_clause(),
                     ast::Struct(it) => it.get_or_create_where_clause(),
+                    ast::TypeAlias(it) => it.get_or_create_where_clause(),
                     _ => return,
                 }
             };
 
-            for toc_param in type_param_list.type_or_const_params() {
-                let type_param = match toc_param {
-                    ast::TypeOrConstParam::Type(x) => x,
-                    ast::TypeOrConstParam::Const(_) => continue,
+            for generic_param in type_param_list.generic_params() {
+                let param: &dyn HasTypeBounds = match &generic_param {
+                    ast::GenericParam::TypeParam(t) => t,
+                    ast::GenericParam::LifetimeParam(l) => l,
+                    ast::GenericParam::ConstParam(_) => continue,
                 };
-                if let Some(tbl) = type_param.type_bound_list() {
-                    if let Some(predicate) = build_predicate(type_param) {
+                if let Some(tbl) = param.type_bound_list() {
+                    if let Some(predicate) = build_predicate(generic_param) {
                         where_clause.add_predicate(predicate)
                     }
                     tbl.remove()
@@ -76,9 +81,23 @@ pub(crate) fn move_bounds_to_where_clause(
     )
 }
 
-fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
-    let path = make::ext::ident_path(&param.name()?.syntax().to_string());
-    let predicate = make::where_pred(make::ty_path(path), param.type_bound_list()?.bounds());
+fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> {
+    let target = match &param {
+        ast::GenericParam::TypeParam(t) => {
+            Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string())))
+        }
+        ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?),
+        ast::GenericParam::ConstParam(_) => return None,
+    };
+    let predicate = make::where_pred(
+        target,
+        match param {
+            ast::GenericParam::TypeParam(t) => t.type_bound_list()?,
+            ast::GenericParam::LifetimeParam(l) => l.type_bound_list()?,
+            ast::GenericParam::ConstParam(_) => return None,
+        }
+        .bounds(),
+    );
     Some(predicate.clone_for_update())
 }
 
@@ -123,4 +142,13 @@ mod tests {
             r#"struct Pair<T>(T, T) where T: u32;"#,
         );
     }
+
+    #[test]
+    fn move_bounds_to_where_clause_trait() {
+        check_assist(
+            move_bounds_to_where_clause,
+            r#"trait T<'a: 'static, $0T: u32> {}"#,
+            r#"trait T<'a, T> where 'a: 'static, T: u32 {}"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 1baf814ca68..16debc4d728 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,6 +1,9 @@
 use std::collections::hash_map::Entry;
 
-use hir::{FileRange, InFile, InRealFile, Module, ModuleSource};
+use hir::{
+    FileRange, InFile, InRealFile, Module, ModuleDef, ModuleSource, PathResolution,
+    PathResolutionPerNs,
+};
 use ide_db::text_edit::TextRange;
 use ide_db::{
     FxHashMap, RootDatabase,
@@ -77,22 +80,17 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
             };
 
             // Get the actual definition associated with this use item.
-            let res = match ctx.sema.resolve_path(&path) {
-                Some(x) => x,
-                None => {
+            let res = match ctx.sema.resolve_path_per_ns(&path) {
+                Some(x) if x.any().is_some() => x,
+                Some(_) | None => {
                     return None;
                 }
             };
 
-            let def = match res {
-                hir::PathResolution::Def(d) => Definition::from(d),
-                _ => return None,
-            };
-
             if u.star_token().is_some() {
                 // Check if any of the children of this module are used
-                let def_mod = match def {
-                    Definition::Module(module) => module,
+                let def_mod = match res.type_ns {
+                    Some(PathResolution::Def(ModuleDef::Module(module))) => module,
                     _ => return None,
                 };
 
@@ -105,21 +103,13 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
                     })
                     .any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
                 {
-                    return Some(u);
-                }
-            } else if let Definition::Trait(ref t) = def {
-                // If the trait or any item is used.
-                if !std::iter::once((def, u.rename()))
-                    .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
-                    .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
-                {
-                    return Some(u);
+                    Some(u)
+                } else {
+                    None
                 }
-            } else if !used_once_in_scope(ctx, def, u.rename(), scope) {
-                return Some(u);
+            } else {
+                is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u)
             }
-
-            None
         })
         .peekable();
 
@@ -141,6 +131,52 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     }
 }
 
+fn is_path_per_ns_unused_in_scope(
+    ctx: &AssistContext<'_>,
+    u: &ast::UseTree,
+    scope: &mut Vec<SearchScope>,
+    path: &PathResolutionPerNs,
+) -> bool {
+    if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns {
+        if is_trait_unused_in_scope(ctx, u, scope, t) {
+            let path = [path.value_ns, path.macro_ns];
+            is_path_unused_in_scope(ctx, u, scope, &path)
+        } else {
+            false
+        }
+    } else {
+        let path = [path.type_ns, path.value_ns, path.macro_ns];
+        is_path_unused_in_scope(ctx, u, scope, &path)
+    }
+}
+
+fn is_path_unused_in_scope(
+    ctx: &AssistContext<'_>,
+    u: &ast::UseTree,
+    scope: &mut Vec<SearchScope>,
+    path: &[Option<PathResolution>],
+) -> bool {
+    !path
+        .iter()
+        .filter_map(|path| *path)
+        .filter_map(|res| match res {
+            PathResolution::Def(d) => Some(Definition::from(d)),
+            _ => None,
+        })
+        .any(|def| used_once_in_scope(ctx, def, u.rename(), scope))
+}
+
+fn is_trait_unused_in_scope(
+    ctx: &AssistContext<'_>,
+    u: &ast::UseTree,
+    scope: &mut Vec<SearchScope>,
+    t: &hir::Trait,
+) -> bool {
+    !std::iter::once((Definition::Trait(*t), u.rename()))
+        .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
+        .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
+}
+
 fn used_once_in_scope(
     ctx: &AssistContext<'_>,
     def: Definition,
@@ -1012,4 +1048,110 @@ fn test(_: Bar) {
 "#,
         );
     }
+
+    #[test]
+    fn test_unused_macro() {
+        check_assist(
+            remove_unused_imports,
+            r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /main.rs crate:main deps:foo
+use foo::m;$0
+fn main() {}
+"#,
+            r#"
+fn main() {}
+"#,
+        );
+
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /main.rs crate:main deps:foo
+use foo::m;$0
+fn main() {
+    m!();
+}
+"#,
+        );
+
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /bar.rs crate:bar deps:foo
+pub use foo::m;
+fn m() {}
+
+
+//- /main.rs crate:main deps:bar
+use bar::m;$0
+fn main() {
+    m!();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_conflict_derive_macro() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub trait DeriveIdentity {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+#[derive(DeriveIdentity)]
+struct S;
+"#,
+        );
+
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub fn DeriveIdentity() {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+#[derive(DeriveIdentity)]
+struct S;
+"#,
+        );
+
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub fn DeriveIdentity() {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+fn main() {
+    DeriveIdentity();
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs
new file mode 100644
index 00000000000..7b5adc1858b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs
@@ -0,0 +1,156 @@
+use ide_db::assists::AssistId;
+use syntax::{
+    AstNode,
+    ast::{self, GenericArg, HasGenericArgs},
+};
+
+use crate::{AssistContext, Assists};
+
+// Assist: unwrap_type_to_generic_arg
+//
+// This assist unwraps a type into its generic type argument.
+//
+// ```
+// fn foo() -> $0Option<i32> {
+//     todo!()
+// }
+// ```
+// ->
+// ```
+// fn foo() -> i32 {
+//     todo!()
+// }
+// ```
+pub(crate) fn unwrap_type_to_generic_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let path_type = ctx.find_node_at_offset::<ast::PathType>()?;
+    let path = path_type.path()?;
+    let segment = path.segment()?;
+    let args_list = segment.generic_arg_list()?;
+
+    let mut generic_arg = None;
+
+    for arg in args_list.generic_args() {
+        match arg {
+            GenericArg::ConstArg(_) | GenericArg::LifetimeArg(_) => (),
+            GenericArg::TypeArg(arg) if generic_arg.is_none() => {
+                generic_arg = Some(arg);
+            }
+            _ => return None,
+        }
+    }
+
+    let generic_arg = generic_arg?;
+
+    acc.add(
+        AssistId::refactor_extract("unwrap_type_to_generic_arg"),
+        format!("Unwrap type to type argument {generic_arg}"),
+        path_type.syntax().text_range(),
+        |builder| {
+            let mut editor = builder.make_editor(path_type.syntax());
+            editor.replace(path_type.syntax(), generic_arg.syntax());
+
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    #[test]
+    fn test_unwrap_type_to_generic_arg() {
+        check_assist(
+            unwrap_type_to_generic_arg,
+            r#"
+//- minicore: option
+fn foo() -> $0Option<i32> {
+    todo!()
+}
+"#,
+            r#"
+fn foo() -> i32 {
+    todo!()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_type_to_generic_arg_not_applicable_for_non_generic_arg_list() {
+        check_assist_not_applicable(
+            unwrap_type_to_generic_arg,
+            r#"
+fn foo() -> $0i32 {}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_type_to_generic_arg_not_applicable_for_multiple_generic_args() {
+        check_assist_not_applicable(
+            unwrap_type_to_generic_arg,
+            r#"
+//- minicore: result
+fn foo() -> $0Result<i32, ()> {
+    todo!()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_type_to_generic_arg_with_lifetime_and_const() {
+        check_assist(
+            unwrap_type_to_generic_arg,
+            r#"
+enum Foo<'a, T, const N: usize> {
+    Bar(T),
+    Baz(&'a [T; N]),
+}
+
+fn test<'a>() -> $0Foo<'a, i32, 3> {
+    todo!()
+}
+"#,
+            r#"
+enum Foo<'a, T, const N: usize> {
+    Bar(T),
+    Baz(&'a [T; N]),
+}
+
+fn test<'a>() -> i32 {
+    todo!()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_type_to_generic_arg_in_let_stmt() {
+        check_assist(
+            unwrap_type_to_generic_arg,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+fn test() {
+    let foo: $0Foo<i32> = todo!();
+}
+"#,
+            r#"
+enum Foo<T> {
+    Bar(T),
+    Baz,
+}
+
+fn test() {
+    let foo: i32 = todo!();
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 627ed37b04e..2395091b6f2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -229,6 +229,7 @@ mod handlers {
     mod unwrap_block;
     mod unwrap_return_type;
     mod unwrap_tuple;
+    mod unwrap_type_to_generic_arg;
     mod wrap_return_type;
     mod wrap_unwrap_cfg_attr;
 
@@ -369,6 +370,7 @@ mod handlers {
             unwrap_block::unwrap_block,
             unwrap_return_type::unwrap_return_type,
             unwrap_tuple::unwrap_tuple,
+            unwrap_type_to_generic_arg::unwrap_type_to_generic_arg,
             wrap_return_type::wrap_return_type,
             wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr,
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 01ab0be34b2..76134acb36e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -3482,6 +3482,23 @@ fn main() {
 }
 
 #[test]
+fn doctest_unwrap_type_to_generic_arg() {
+    check_doc_test(
+        "unwrap_type_to_generic_arg",
+        r#####"
+fn foo() -> $0Option<i32> {
+    todo!()
+}
+"#####,
+        r#####"
+fn foo() -> i32 {
+    todo!()
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_wrap_return_type_in_option() {
     check_doc_test(
         "wrap_return_type_in_option",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index cd18b3dcfdc..92cbf411c1e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -13,6 +13,7 @@ use crate::{
 const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
     ("CARGO", "Path to the cargo binary performing the build"),
     ("CARGO_MANIFEST_DIR", "The directory containing the manifest of your package"),
+    ("CARGO_MANIFEST_PATH", "The path to the manifest of your package"),
     ("CARGO_PKG_VERSION", "The full version of your package"),
     ("CARGO_PKG_VERSION_MAJOR", "The major version of your package"),
     ("CARGO_PKG_VERSION_MINOR", "The minor version of your package"),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 54be7d2fbc3..3cdf2112835 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -311,6 +311,8 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
 
     let mut prefix = String::new();
 
+    let mut found_ref_or_deref = false;
+
     while let Some(parent_deref_element) =
         resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
     {
@@ -318,27 +320,26 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
             break;
         }
 
+        found_ref_or_deref = true;
         resulting_element = ast::Expr::from(parent_deref_element);
 
         prefix.insert(0, '*');
     }
 
-    if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
-        if let Some(expr) = first_ref_expr.expr() {
-            resulting_element = expr;
-        }
+    while let Some(parent_ref_element) =
+        resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
+    {
+        found_ref_or_deref = true;
+        let exclusive = parent_ref_element.mut_token().is_some();
+        resulting_element = ast::Expr::from(parent_ref_element);
 
-        while let Some(parent_ref_element) =
-            resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
-        {
-            let exclusive = parent_ref_element.mut_token().is_some();
-            resulting_element = ast::Expr::from(parent_ref_element);
+        prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
+    }
 
-            prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
-        }
-    } else {
-        // If we do not find any ref expressions, restore
+    if !found_ref_or_deref {
+        // If we do not find any ref/deref expressions, restore
         // all the progress of tree climbing
+        prefix.clear();
         resulting_element = initial_element.clone();
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 391e2379dcd..284876ffc88 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -883,9 +883,10 @@ fn classify_name_ref(
             },
             ast::MethodCallExpr(method) => {
                 let receiver = find_opt_node_in_file(original_file, method.receiver());
+                let has_parens = has_parens(&method);
                 let kind = NameRefKind::DotAccess(DotAccess {
                     receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
-                    kind: DotAccessKind::Method { has_parens: method.arg_list().is_some_and(|it| it.l_paren_token().is_some()) },
+                    kind: DotAccessKind::Method { has_parens },
                     receiver,
                     ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
                 });
@@ -1372,7 +1373,7 @@ fn classify_name_ref(
                         }
                     }
 
-                    path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+                    path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
 
                     make_path_kind_expr(it.into())
                 },
@@ -1401,7 +1402,7 @@ fn classify_name_ref(
                         match parent {
                             ast::PathType(it) => make_path_kind_type(it.into()),
                             ast::PathExpr(it) => {
-                                path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+                                path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
 
                                 make_path_kind_expr(it.into())
                             },
@@ -1559,6 +1560,30 @@ fn classify_name_ref(
     Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
 }
 
+/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
+/// ```ignore
+/// value.method|
+/// (1, 2, 3)
+/// ```
+/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
+/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
+/// are on the next line, consider them non-existent.
+fn has_parens(node: &dyn HasArgList) -> bool {
+    let Some(arg_list) = node.arg_list() else { return false };
+    if arg_list.l_paren_token().is_none() {
+        return false;
+    }
+    let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
+        it.prev_sibling_or_token()
+    });
+    prev_siblings
+        .take_while(|syntax| syntax.kind().is_trivia())
+        .filter_map(|syntax| {
+            syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
+        })
+        .all(|whitespace| !whitespace.text().contains('\n'))
+}
+
 fn pattern_context_for(
     sema: &Semantics<'_, RootDatabase>,
     original_file: &SyntaxNode,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index d5137949d42..e5467767d42 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -2126,3 +2126,70 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn call_parens_with_newline() {
+    check_edit(
+        "foo",
+        r#"
+fn foo(v: i32) {}
+
+fn bar() {
+    foo$0
+    ()
+}
+    "#,
+        r#"
+fn foo(v: i32) {}
+
+fn bar() {
+    foo(${1:v});$0
+    ()
+}
+    "#,
+    );
+    check_edit(
+        "foo",
+        r#"
+struct Foo;
+impl Foo {
+    fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+    Foo.foo$0
+    ()
+}
+    "#,
+        r#"
+struct Foo;
+impl Foo {
+    fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+    Foo.foo(${1:v});$0
+    ()
+}
+    "#,
+    );
+}
+
+#[test]
+fn dbg_too_many_asterisks() {
+    check_edit(
+        "dbg",
+        r#"
+fn main() {
+    let x = &42;
+    let y = *x.$0;
+}
+    "#,
+        r#"
+fn main() {
+    let x = &42;
+    let y = dbg!(*x);
+}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index bf4f541ff54..d5db1c481b6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -6,7 +6,7 @@
 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 
 use crate::RootDatabase;
-use crate::documentation::{Documentation, HasDocs};
+use crate::documentation::{DocsRangeMap, Documentation, HasDocs};
 use crate::famous_defs::FamousDefs;
 use arrayvec::ArrayVec;
 use either::Either;
@@ -21,7 +21,7 @@ use hir::{
 use span::Edition;
 use stdx::{format_to, impl_from};
 use syntax::{
-    SyntaxKind, SyntaxNode, SyntaxToken,
+    SyntaxKind, SyntaxNode, SyntaxToken, TextSize,
     ast::{self, AstNode},
     match_ast,
 };
@@ -210,29 +210,40 @@ impl Definition {
         famous_defs: Option<&FamousDefs<'_, '_>>,
         display_target: DisplayTarget,
     ) -> Option<Documentation> {
+        self.docs_with_rangemap(db, famous_defs, display_target).map(|(docs, _)| docs)
+    }
+
+    pub fn docs_with_rangemap(
+        &self,
+        db: &RootDatabase,
+        famous_defs: Option<&FamousDefs<'_, '_>>,
+        display_target: DisplayTarget,
+    ) -> Option<(Documentation, Option<DocsRangeMap>)> {
         let docs = match self {
-            Definition::Macro(it) => it.docs(db),
-            Definition::Field(it) => it.docs(db),
-            Definition::Module(it) => it.docs(db),
-            Definition::Crate(it) => it.docs(db),
-            Definition::Function(it) => it.docs(db),
-            Definition::Adt(it) => it.docs(db),
-            Definition::Variant(it) => it.docs(db),
-            Definition::Const(it) => it.docs(db),
-            Definition::Static(it) => it.docs(db),
-            Definition::Trait(it) => it.docs(db),
-            Definition::TraitAlias(it) => it.docs(db),
+            Definition::Macro(it) => it.docs_with_rangemap(db),
+            Definition::Field(it) => it.docs_with_rangemap(db),
+            Definition::Module(it) => it.docs_with_rangemap(db),
+            Definition::Crate(it) => it.docs_with_rangemap(db),
+            Definition::Function(it) => it.docs_with_rangemap(db),
+            Definition::Adt(it) => it.docs_with_rangemap(db),
+            Definition::Variant(it) => it.docs_with_rangemap(db),
+            Definition::Const(it) => it.docs_with_rangemap(db),
+            Definition::Static(it) => it.docs_with_rangemap(db),
+            Definition::Trait(it) => it.docs_with_rangemap(db),
+            Definition::TraitAlias(it) => it.docs_with_rangemap(db),
             Definition::TypeAlias(it) => {
-                it.docs(db).or_else(|| {
+                it.docs_with_rangemap(db).or_else(|| {
                     // docs are missing, try to fall back to the docs of the aliased item.
                     let adt = it.ty(db).as_adt()?;
-                    let docs = adt.docs(db)?;
-                    let docs = format!(
-                        "*This is the documentation for* `{}`\n\n{}",
-                        adt.display(db, display_target),
-                        docs.as_str()
+                    let (docs, range_map) = adt.docs_with_rangemap(db)?;
+                    let header_docs = format!(
+                        "*This is the documentation for* `{}`\n\n",
+                        adt.display(db, display_target)
                     );
-                    Some(Documentation::new(docs))
+                    let offset = TextSize::new(header_docs.len() as u32);
+                    let range_map = range_map.shift_docstring_line_range(offset);
+                    let docs = header_docs + docs.as_str();
+                    Some((Documentation::new(docs), range_map))
                 })
             }
             Definition::BuiltinType(it) => {
@@ -241,17 +252,17 @@ impl Definition {
                     let primitive_mod =
                         format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
                     let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
-                    doc_owner.docs(fd.0.db)
+                    doc_owner.docs_with_rangemap(fd.0.db)
                 })
             }
             Definition::BuiltinLifetime(StaticLifetime) => None,
             Definition::Local(_) => None,
             Definition::SelfType(impl_def) => {
-                impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
+                impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
             }
             Definition::GenericParam(_) => None,
             Definition::Label(_) => None,
-            Definition::ExternCrateDecl(it) => it.docs(db),
+            Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
 
             Definition::BuiltinAttr(it) => {
                 let name = it.name(db);
@@ -276,7 +287,8 @@ impl Definition {
                         name_value_str
                     );
                 }
-                Some(Documentation::new(docs.replace('*', "\\*")))
+
+                return Some((Documentation::new(docs.replace('*', "\\*")), None));
             }
             Definition::ToolModule(_) => None,
             Definition::DeriveHelper(_) => None,
@@ -291,8 +303,9 @@ impl Definition {
             let trait_ = assoc.implemented_trait(db)?;
             let name = Some(assoc.name(db)?);
             let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
-            item.docs(db)
+            item.docs_with_rangemap(db)
         })
+        .map(|(docs, range_map)| (docs, Some(range_map)))
     }
 
     pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index ef2c83992c0..30c355f8b3f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -34,11 +34,13 @@ impl From<Documentation> for String {
 
 pub trait HasDocs: HasAttrs {
     fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)>;
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option<hir::Namespace>,
+        is_inner_doc: bool,
     ) -> Option<hir::DocLinkDef>;
 }
 /// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
@@ -53,7 +55,7 @@ pub struct DocsRangeMap {
 
 impl DocsRangeMap {
     /// Maps a [`TextRange`] relative to the documentation string back to its AST range
-    pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
+    pub fn map(&self, range: TextRange) -> Option<(InFile<TextRange>, AttrId)> {
         let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
         let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
         if !line_docs_range.contains_range(range) {
@@ -71,7 +73,7 @@ impl DocsRangeMap {
                     text_range.end() + original_line_src_range.start() + relative_range.start(),
                     string.syntax().text_range().len().min(range.len()),
                 );
-                Some(InFile { file_id, value: range })
+                Some((InFile { file_id, value: range }, idx))
             }
             Either::Right(comment) => {
                 let text_range = comment.syntax().text_range();
@@ -82,10 +84,22 @@ impl DocsRangeMap {
                         + relative_range.start(),
                     text_range.len().min(range.len()),
                 );
-                Some(InFile { file_id, value: range })
+                Some((InFile { file_id, value: range }, idx))
             }
         }
     }
+
+    pub fn shift_docstring_line_range(self, offset: TextSize) -> DocsRangeMap {
+        let mapping = self
+            .mapping
+            .into_iter()
+            .map(|(buf_offset, id, base_offset)| {
+                let buf_offset = buf_offset.checked_add(offset).unwrap();
+                (buf_offset, id, base_offset)
+            })
+            .collect_vec();
+        DocsRangeMap { source_map: self.source_map, mapping }
+    }
 }
 
 pub fn docs_with_rangemap(
@@ -161,13 +175,20 @@ macro_rules! impl_has_docs {
             fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                 docs_from_attrs(&self.attrs(db)).map(Documentation)
             }
+            fn docs_with_rangemap(
+                self,
+                db: &dyn HirDatabase,
+            ) -> Option<(Documentation, DocsRangeMap)> {
+                docs_with_rangemap(db, &self.attrs(db))
+            }
             fn resolve_doc_path(
                 self,
                 db: &dyn HirDatabase,
                 link: &str,
-                ns: Option<hir::Namespace>
+                ns: Option<hir::Namespace>,
+                is_inner_doc: bool,
             ) -> Option<hir::DocLinkDef> {
-                resolve_doc_path_on(db, self, link, ns)
+                resolve_doc_path_on(db, self, link, ns, is_inner_doc)
             }
         }
     )*};
@@ -184,13 +205,21 @@ macro_rules! impl_has_docs_enum {
             fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                 hir::$enum::$variant(self).docs(db)
             }
+
+            fn docs_with_rangemap(
+                self,
+                db: &dyn HirDatabase,
+            ) -> Option<(Documentation, DocsRangeMap)> {
+                hir::$enum::$variant(self).docs_with_rangemap(db)
+            }
             fn resolve_doc_path(
                 self,
                 db: &dyn HirDatabase,
                 link: &str,
-                ns: Option<hir::Namespace>
+                ns: Option<hir::Namespace>,
+                is_inner_doc: bool,
             ) -> Option<hir::DocLinkDef> {
-                hir::$enum::$variant(self).resolve_doc_path(db, link, ns)
+                hir::$enum::$variant(self).resolve_doc_path(db, link, ns, is_inner_doc)
             }
         }
     )*};
@@ -207,16 +236,25 @@ impl HasDocs for hir::AssocItem {
         }
     }
 
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+        match self {
+            hir::AssocItem::Function(it) => it.docs_with_rangemap(db),
+            hir::AssocItem::Const(it) => it.docs_with_rangemap(db),
+            hir::AssocItem::TypeAlias(it) => it.docs_with_rangemap(db),
+        }
+    }
+
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option<hir::Namespace>,
+        is_inner_doc: bool,
     ) -> Option<hir::DocLinkDef> {
         match self {
-            hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
-            hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
-            hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
+            hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+            hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+            hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
         }
     }
 }
@@ -238,13 +276,36 @@ impl HasDocs for hir::ExternCrateDecl {
         }
         .map(Documentation::new)
     }
+
+    fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+        let crate_docs = docs_with_rangemap(db, &self.resolved_crate(db)?.root_module().attrs(db));
+        let decl_docs = docs_with_rangemap(db, &self.attrs(db));
+        match (decl_docs, crate_docs) {
+            (None, None) => None,
+            (Some(decl_docs), None) => Some(decl_docs),
+            (None, Some(crate_docs)) => Some(crate_docs),
+            (
+                Some((Documentation(mut decl_docs), mut decl_range_map)),
+                Some((Documentation(crate_docs), crate_range_map)),
+            ) => {
+                decl_docs.push('\n');
+                decl_docs.push('\n');
+                let offset = TextSize::new(decl_docs.len() as u32);
+                decl_docs += &crate_docs;
+                let crate_range_map = crate_range_map.shift_docstring_line_range(offset);
+                decl_range_map.mapping.extend(crate_range_map.mapping);
+                Some((Documentation(decl_docs), decl_range_map))
+            }
+        }
+    }
     fn resolve_doc_path(
         self,
         db: &dyn HirDatabase,
         link: &str,
         ns: Option<hir::Namespace>,
+        is_inner_doc: bool,
     ) -> Option<hir::DocLinkDef> {
-        resolve_doc_path_on(db, self, link, ns)
+        resolve_doc_path_on(db, self, link, ns, is_inner_doc)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index cbe31405ab7..5356614dce5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -2,12 +2,10 @@
 //! sometimes is counter productive when, for example, the first goto definition
 //! request takes longer to compute. This module implements prepopulation of
 //! various caches, it's not really advanced at the moment.
-mod topologic_sort;
-
-use std::time::Duration;
+use std::panic::AssertUnwindSafe;
 
 use hir::{Symbol, db::DefDatabase};
-use itertools::Itertools;
+use rustc_hash::FxHashMap;
 use salsa::{Cancelled, Database};
 
 use crate::{
@@ -35,59 +33,114 @@ pub fn parallel_prime_caches(
 ) {
     let _p = tracing::info_span!("parallel_prime_caches").entered();
 
-    let mut crates_to_prime = {
-        // FIXME: We already have the crate list topologically sorted (but without the things
-        // `TopologicalSortIter` gives us). Maybe there is a way to avoid using it and rip it out
-        // of the codebase?
-        let mut builder = topologic_sort::TopologicalSortIter::builder();
-
-        for &crate_id in db.all_crates().iter() {
-            builder.add(crate_id, crate_id.data(db).dependencies.iter().map(|d| d.crate_id));
-        }
-
-        builder.build()
-    };
-
     enum ParallelPrimeCacheWorkerProgress {
-        BeginCrate { crate_id: Crate, crate_name: Symbol },
-        EndCrate { crate_id: Crate },
+        BeginCrateDefMap { crate_id: Crate, crate_name: Symbol },
+        EndCrateDefMap { crate_id: Crate },
+        EndCrateImportMap,
+        EndModuleSymbols,
         Cancelled(Cancelled),
     }
 
-    // We split off def map computation from other work,
-    // as the def map is the relevant one. Once the defmaps are computed
-    // the project is ready to go, the other indices are just nice to have for some IDE features.
-    #[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone)]
-    enum PrimingPhase {
-        DefMap,
-        ImportMap,
-        CrateSymbols,
-    }
+    // The setup here is a bit complicated. We try to make best use of compute resources.
+    // The idea is that if we have a def map available to compute, we should do that first.
+    // This is because def map is a dependency of both import map and symbols. So if we have
+    // e.g. a def map and a symbols, if we compute the def map we can, after it completes,
+    // compute the def maps of dependencies, the existing symbols and the symbols of the
+    // new crate, all in parallel. But if we compute the symbols, after that we will only
+    // have the def map to compute, and the rest of the CPU cores will rest, which is not
+    // good.
+    // However, it's better to compute symbols/import map than to compute a def map that
+    // isn't ready yet, because one of its dependencies hasn't yet completed its def map.
+    // Such def map will just block on the dependency, which is just wasted time. So better
+    // to compute the symbols/import map of an already computed def map in that time.
+
+    let (reverse_deps, mut to_be_done_deps) = {
+        let all_crates = db.all_crates();
+        let to_be_done_deps = all_crates
+            .iter()
+            .map(|&krate| (krate, krate.data(db).dependencies.len() as u32))
+            .collect::<FxHashMap<_, _>>();
+        let mut reverse_deps =
+            all_crates.iter().map(|&krate| (krate, Vec::new())).collect::<FxHashMap<_, _>>();
+        for &krate in &*all_crates {
+            for dep in &krate.data(db).dependencies {
+                reverse_deps.get_mut(&dep.crate_id).unwrap().push(krate);
+            }
+        }
+        (reverse_deps, to_be_done_deps)
+    };
 
-    let (work_sender, progress_receiver) = {
+    let (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver) = {
         let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
-        let (work_sender, work_receiver) = crossbeam_channel::unbounded();
-        let prime_caches_worker = move |db: RootDatabase| {
-            while let Ok((crate_id, crate_name, kind)) = work_receiver.recv() {
-                progress_sender
-                    .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
-
-                let cancelled = Cancelled::catch(|| match kind {
-                    PrimingPhase::DefMap => _ = db.crate_def_map(crate_id),
-                    PrimingPhase::ImportMap => _ = db.import_map(crate_id),
-                    PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()),
-                });
+        let (def_map_work_sender, def_map_work_receiver) = crossbeam_channel::unbounded();
+        let (import_map_work_sender, import_map_work_receiver) = crossbeam_channel::unbounded();
+        let (symbols_work_sender, symbols_work_receiver) = crossbeam_channel::unbounded();
+        let prime_caches_worker =
+            move |db: RootDatabase| {
+                let handle_def_map = |crate_id, crate_name| {
+                    progress_sender.send(ParallelPrimeCacheWorkerProgress::BeginCrateDefMap {
+                        crate_id,
+                        crate_name,
+                    })?;
 
-                match cancelled {
-                    Ok(()) => progress_sender
-                        .send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?,
-                    Err(cancelled) => progress_sender
-                        .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
-                }
-            }
+                    let cancelled = Cancelled::catch(|| _ = hir::crate_def_map(&db, crate_id));
 
-            Ok::<_, crossbeam_channel::SendError<_>>(())
-        };
+                    match cancelled {
+                        Ok(()) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id })?,
+                        Err(cancelled) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+                    }
+
+                    Ok::<_, crossbeam_channel::SendError<_>>(())
+                };
+                let handle_import_map = |crate_id| {
+                    let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id));
+
+                    match cancelled {
+                        Ok(()) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::EndCrateImportMap)?,
+                        Err(cancelled) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+                    }
+
+                    Ok::<_, crossbeam_channel::SendError<_>>(())
+                };
+                let handle_symbols = |module| {
+                    let cancelled =
+                        Cancelled::catch(AssertUnwindSafe(|| _ = db.module_symbols(module)));
+
+                    match cancelled {
+                        Ok(()) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::EndModuleSymbols)?,
+                        Err(cancelled) => progress_sender
+                            .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+                    }
+
+                    Ok::<_, crossbeam_channel::SendError<_>>(())
+                };
+
+                loop {
+                    db.unwind_if_revision_cancelled();
+
+                    // Biased because we want to prefer def maps.
+                    crossbeam_channel::select_biased! {
+                        recv(def_map_work_receiver) -> work => {
+                            let Ok((crate_id, crate_name)) = work else { break };
+                            handle_def_map(crate_id, crate_name)?;
+                        }
+                        recv(import_map_work_receiver) -> work => {
+                            let Ok(crate_id) = work else { break };
+                            handle_import_map(crate_id)?;
+                        }
+                        recv(symbols_work_receiver) -> work => {
+                            let Ok(module) = work else { break };
+                            handle_symbols(module)?;
+                        }
+                    }
+                }
+                Ok::<_, crossbeam_channel::SendError<_>>(())
+            };
 
         for id in 0..num_worker_threads {
             stdx::thread::Builder::new(
@@ -103,138 +156,121 @@ pub fn parallel_prime_caches(
             .expect("failed to spawn thread");
         }
 
-        (work_sender, progress_receiver)
+        (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver)
     };
 
-    let crates_total = crates_to_prime.pending();
-    let mut crates_done = 0;
+    let crate_def_maps_total = db.all_crates().len();
+    let mut crate_def_maps_done = 0;
+    let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
+    let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
 
     // an index map is used to preserve ordering so we can sort the progress report in order of
     // "longest crate to index" first
     let mut crates_currently_indexing =
         FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
 
-    let mut additional_phases = vec![];
-
-    while crates_done < crates_total {
-        db.unwind_if_revision_cancelled();
-
-        for krate in &mut crates_to_prime {
-            let name = krate.extra_data(db).display_name.as_deref().cloned().unwrap_or_else(|| {
-                Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize)
-            });
-            let origin = &krate.data(db).origin;
-            if origin.is_lang() {
-                additional_phases.push((krate, name.clone(), PrimingPhase::ImportMap));
-            } else if origin.is_local() {
-                // Compute the symbol search index.
-                // This primes the cache for `ide_db::symbol_index::world_symbols()`.
-                //
-                // We do this for workspace crates only (members of local_roots), because doing it
-                // for all dependencies could be *very* unnecessarily slow in a large project.
-                //
-                // FIXME: We should do it unconditionally if the configuration is set to default to
-                // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
-                // would need to pipe that configuration information down here.
-                additional_phases.push((krate, name.clone(), PrimingPhase::CrateSymbols));
-            }
-
-            work_sender.send((krate, name, PrimingPhase::DefMap)).ok();
+    for (&krate, &to_be_done_deps) in &to_be_done_deps {
+        if to_be_done_deps != 0 {
+            continue;
         }
 
-        // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
-        // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
-        // if this thread exits, and closes the work channel.
-        let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
-            Ok(p) => p,
-            Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
-                continue;
-            }
-            Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
-                // all our workers have exited, mark us as finished and exit
-                cb(ParallelPrimeCachesProgress {
-                    crates_currently_indexing: vec![],
-                    crates_done,
-                    crates_total: crates_done,
-                    work_type: "Indexing",
-                });
-                return;
-            }
-        };
-        match worker_progress {
-            ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
-                crates_currently_indexing.insert(crate_id, crate_name);
-            }
-            ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
-                crates_currently_indexing.swap_remove(&crate_id);
-                crates_to_prime.mark_done(crate_id);
-                crates_done += 1;
-            }
-            ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
-                // Cancelled::throw should probably be public
-                std::panic::resume_unwind(Box::new(cancelled));
-            }
-        };
+        let name = crate_name(db, krate);
+        def_map_work_sender.send((krate, name)).ok();
+    }
+
+    while crate_def_maps_done < crate_def_maps_total
+        || crate_import_maps_done < crate_import_maps_total
+        || module_symbols_done < module_symbols_total
+    {
+        db.unwind_if_revision_cancelled();
 
         let progress = ParallelPrimeCachesProgress {
             crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
-            crates_done,
-            crates_total,
+            crates_done: crate_def_maps_done,
+            crates_total: crate_def_maps_total,
             work_type: "Indexing",
         };
 
         cb(progress);
-    }
-
-    let mut crates_done = 0;
-    let crates_total = additional_phases.len();
-    for w in additional_phases.into_iter().sorted_by_key(|&(_, _, phase)| phase) {
-        work_sender.send(w).ok();
-    }
-
-    while crates_done < crates_total {
-        db.unwind_if_revision_cancelled();
 
-        // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
-        // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
-        // if this thread exits, and closes the work channel.
-        let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
+        // Biased to prefer progress updates (and because it's faster).
+        let progress = match progress_receiver.recv() {
             Ok(p) => p,
-            Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
-                continue;
-            }
-            Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
+            Err(crossbeam_channel::RecvError) => {
                 // all our workers have exited, mark us as finished and exit
                 cb(ParallelPrimeCachesProgress {
                     crates_currently_indexing: vec![],
-                    crates_done,
-                    crates_total: crates_done,
-                    work_type: "Populating symbols",
+                    crates_done: crate_def_maps_done,
+                    crates_total: crate_def_maps_done,
+                    work_type: "Done",
                 });
                 return;
             }
         };
-        match worker_progress {
-            ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
+
+        match progress {
+            ParallelPrimeCacheWorkerProgress::BeginCrateDefMap { crate_id, crate_name } => {
                 crates_currently_indexing.insert(crate_id, crate_name);
             }
-            ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
+            ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id } => {
                 crates_currently_indexing.swap_remove(&crate_id);
-                crates_done += 1;
+                crate_def_maps_done += 1;
+
+                // Fire ready dependencies.
+                for &dep in &reverse_deps[&crate_id] {
+                    let to_be_done = to_be_done_deps.get_mut(&dep).unwrap();
+                    *to_be_done -= 1;
+                    if *to_be_done == 0 {
+                        let dep_name = crate_name(db, dep);
+                        def_map_work_sender.send((dep, dep_name)).ok();
+                    }
+                }
+
+                if crate_def_maps_done == crate_def_maps_total {
+                    cb(ParallelPrimeCachesProgress {
+                        crates_currently_indexing: vec![],
+                        crates_done: crate_def_maps_done,
+                        crates_total: crate_def_maps_done,
+                        work_type: "Collecting Symbols",
+                    });
+                }
+
+                let origin = &crate_id.data(db).origin;
+                if origin.is_lang() {
+                    crate_import_maps_total += 1;
+                    import_map_work_sender.send(crate_id).ok();
+                } else if origin.is_local() {
+                    // Compute the symbol search index.
+                    // This primes the cache for `ide_db::symbol_index::world_symbols()`.
+                    //
+                    // We do this for workspace crates only (members of local_roots), because doing it
+                    // for all dependencies could be *very* unnecessarily slow in a large project.
+                    //
+                    // FIXME: We should do it unconditionally if the configuration is set to default to
+                    // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
+                    // would need to pipe that configuration information down here.
+                    let modules = hir::Crate::from(crate_id).modules(db);
+                    module_symbols_total += modules.len();
+                    for module in modules {
+                        symbols_work_sender.send(module).ok();
+                    }
+                }
             }
+            ParallelPrimeCacheWorkerProgress::EndCrateImportMap => crate_import_maps_done += 1,
+            ParallelPrimeCacheWorkerProgress::EndModuleSymbols => module_symbols_done += 1,
             ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
                 // Cancelled::throw should probably be public
                 std::panic::resume_unwind(Box::new(cancelled));
             }
-        };
-
-        let progress = ParallelPrimeCachesProgress {
-            crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
-            crates_done,
-            crates_total,
-            work_type: "Populating symbols",
-        };
-
-        cb(progress);
+        }
     }
 }
+
+fn crate_name(db: &RootDatabase, krate: Crate) -> Symbol {
+    krate
+        .extra_data(db)
+        .display_name
+        .as_deref()
+        .cloned()
+        .unwrap_or_else(|| Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize))
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs
deleted file mode 100644
index c8a03863103..00000000000
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-//! helper data structure to schedule work for parallel prime caches.
-use std::{collections::VecDeque, hash::Hash};
-
-use crate::FxHashMap;
-
-pub(crate) struct TopologicSortIterBuilder<T> {
-    nodes: FxHashMap<T, Entry<T>>,
-}
-
-// this implementation has different bounds on T than would be implied by #[derive(Default)]
-impl<T> Default for TopologicSortIterBuilder<T>
-where
-    T: Copy + Eq + PartialEq + Hash,
-{
-    fn default() -> Self {
-        Self { nodes: Default::default() }
-    }
-}
-
-impl<T> TopologicSortIterBuilder<T>
-where
-    T: Copy + Eq + PartialEq + Hash,
-{
-    fn get_or_create_entry(&mut self, item: T) -> &mut Entry<T> {
-        self.nodes.entry(item).or_default()
-    }
-
-    pub(crate) fn add(&mut self, item: T, predecessors: impl IntoIterator<Item = T>) {
-        let mut num_predecessors = 0;
-
-        for predecessor in predecessors.into_iter() {
-            self.get_or_create_entry(predecessor).successors.push(item);
-            num_predecessors += 1;
-        }
-
-        let entry = self.get_or_create_entry(item);
-        entry.num_predecessors += num_predecessors;
-    }
-
-    pub(crate) fn build(self) -> TopologicalSortIter<T> {
-        let ready = self
-            .nodes
-            .iter()
-            .filter_map(
-                |(item, entry)| if entry.num_predecessors == 0 { Some(*item) } else { None },
-            )
-            .collect();
-
-        TopologicalSortIter { nodes: self.nodes, ready }
-    }
-}
-
-pub(crate) struct TopologicalSortIter<T> {
-    ready: VecDeque<T>,
-    nodes: FxHashMap<T, Entry<T>>,
-}
-
-impl<T> TopologicalSortIter<T>
-where
-    T: Copy + Eq + PartialEq + Hash,
-{
-    pub(crate) fn builder() -> TopologicSortIterBuilder<T> {
-        TopologicSortIterBuilder::default()
-    }
-
-    pub(crate) fn pending(&self) -> usize {
-        self.nodes.len()
-    }
-
-    pub(crate) fn mark_done(&mut self, item: T) {
-        let entry = self.nodes.remove(&item).expect("invariant: unknown item marked as done");
-
-        for successor in entry.successors {
-            let succ_entry = self
-                .nodes
-                .get_mut(&successor)
-                .expect("invariant: unknown successor referenced by entry");
-
-            succ_entry.num_predecessors -= 1;
-            if succ_entry.num_predecessors == 0 {
-                self.ready.push_back(successor);
-            }
-        }
-    }
-}
-
-impl<T> Iterator for TopologicalSortIter<T> {
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.ready.pop_front()
-    }
-}
-
-struct Entry<T> {
-    successors: Vec<T>,
-    num_predecessors: usize,
-}
-
-impl<T> Default for Entry<T> {
-    fn default() -> Self {
-        Self { successors: Default::default(), num_predecessors: 0 }
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index b8119e1aab3..fa2a46a0f7c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -390,11 +390,6 @@ pub fn source_edit_from_references(
     let mut edited_ranges = Vec::new();
     for &FileReference { range, ref name, .. } in references {
         let name_range = name.text_range();
-        if name_range.len() != range.len() {
-            // This usage comes from a different token kind that was downmapped to a NameLike in a macro
-            // Renaming this will most likely break things syntax-wise
-            continue;
-        }
         let has_emitted_edit = match name {
             // if the ranges differ then the node is inside a macro call, we can't really attempt
             // to make special rewrites like shorthand syntax and such, so just rename the node in
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
index 92ca7a74184..2a7b0098edf 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
@@ -14,6 +14,7 @@ pub(crate) fn await_outside_of_async(
         format!("`await` is used inside {}, which is not an `async` context", d.location),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
index 9ed85f9f208..ae42a88c313 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
@@ -12,6 +12,7 @@ pub(crate) fn bad_rtn(ctx: &DiagnosticsContext<'_>, d: &hir::BadRtn) -> Diagnost
         "return type notation not allowed in this position yet",
         d.rtn.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index c25b0a7bf7d..cbcaab6c747 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -19,6 +19,7 @@ pub(crate) fn break_outside_of_loop(
         message,
         d.expr.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
index 438dd2fdcb6..b284d9b3510 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
@@ -15,7 +15,6 @@ pub(crate) fn elided_lifetimes_in_path(
             "implicit elided lifetime not allowed here",
             d.generics_or_segment.map(Into::into),
         )
-        .experimental()
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
@@ -23,7 +22,6 @@ pub(crate) fn elided_lifetimes_in_path(
             "hidden lifetime parameters in types are deprecated",
             d.generics_or_segment.map(Into::into),
         )
-        .experimental()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index a6da0fd9c5e..7d2ac373dc0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -15,7 +15,6 @@ pub(crate) fn expected_function(
         format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.display_target)),
         d.call.map(|it| it.into()),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index b617c094983..9ae6f013c70 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -21,6 +21,7 @@ pub(crate) fn generic_args_prohibited(
         describe_reason(d.reason),
         d.args.map(Into::into),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 47e1c84fecd..8611ef653b0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -33,6 +33,7 @@ pub(crate) fn inactive_code(
         message,
         ctx.sema.diagnostics_display_range(d.node),
     )
+    .stable()
     .with_unused(true);
     Some(res)
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
index 0b9a2ec9db3..a0c364b0010 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -19,6 +19,7 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI
         "cannot define inherent `impl` for foreign type".to_owned(),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 289a0765732..38f10c778d6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -29,6 +29,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas
         ),
         InFile::new(d.file, d.ident.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 17c7f75880c..06f35759420 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -28,7 +28,6 @@ pub(crate) fn incorrect_generics_len(
         message,
         d.generics_or_segment.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
index 84496df2d7c..b71586d6be0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
@@ -28,6 +28,7 @@ pub(crate) fn incorrect_generics_order(
         message,
         d.provided_arg.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index d72b21099ce..7a6e98fe1b5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -100,7 +100,7 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
         //     "cannot cast to a pointer of an unknown kind".to_owned(),
         // ),
     };
-    Diagnostic::new(code, message, display_range)
+    Diagnostic::new(code, message, display_range).stable()
 }
 
 // Diagnostic: cast-to-unsized
@@ -113,6 +113,7 @@ pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsiz
         format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
index ab0f5139f10..8b708f229d0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
@@ -15,6 +15,7 @@ pub(crate) fn invalid_derive_target(
         "`derive` may only be applied to `struct`s, `enum`s and `union`s",
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index a2648a1995d..546512a6cf9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -19,6 +19,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
         d.message.clone(),
         display_range,
     )
+    .stable()
 }
 
 // Diagnostic: macro-def-error
@@ -33,6 +34,7 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr
         d.message.clone(),
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
index 0e47fff6f93..701b30b9b59 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
@@ -14,6 +14,7 @@ pub(crate) fn malformed_derive(
         "malformed derive input, derive attributes are of the form `#[derive(Derive1, Derive2, ...)]`",
         display_range,
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 63fd9b4e3f0..25c1e633ba3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -26,6 +26,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count(
         message,
         invalid_args_range(ctx, d.expr_or_pat, d.expected, d.found),
     )
+    .stable()
 }
 
 // Diagnostic: mismatched-arg-count
@@ -42,6 +43,7 @@ pub(crate) fn mismatched_arg_count(
         message,
         invalid_args_range(ctx, d.call_expr, d.expected, d.found),
     )
+    .stable()
 }
 
 fn invalid_args_range(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index a354d123f5a..2b76efb1965 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -47,6 +47,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField
     );
 
     Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr)
+        .stable()
         .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index 8cdbb6384ff..76b30745a04 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -13,7 +13,6 @@ pub(crate) fn missing_lifetime(
         "missing lifetime specifier",
         d.generics_or_segment.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index d3d3c3aa38d..1fc96b78eda 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -13,6 +13,7 @@ pub(crate) fn missing_match_arms(
         format!("missing match arm: {}", d.uncovered_patterns),
         d.scrutinee_expr.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 3c36b455ca9..364bead34ef 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -23,6 +23,7 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
         format!("{operation} is unsafe and requires an unsafe function or block"),
         d.node.map(|it| it.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
@@ -893,4 +894,25 @@ fn main() {
         "#,
         );
     }
+
+    #[test]
+    fn asm_label() {
+        check_diagnostics(
+            r#"
+//- minicore: asm
+fn foo() {
+    unsafe {
+        core::arch::asm!(
+            "jmp {}",
+            label {
+                let p = 0xDEADBEAF as *mut u8;
+                *p = 3;
+             // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
+            },
+        );
+    }
+}
+            "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 780271361d7..01cf5e8fa52 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -11,7 +11,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
         format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
         d.span,
     )
-    .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
+    // spans are broken, and I'm not sure how precise we can detect copy types
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 5d25f2c6a90..8831efa3117 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -55,6 +55,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
             ),
             span,
         )
+        .stable()
         .with_fixes(fixes),
     )
 }
@@ -94,7 +95,7 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Op
             "variable does not need to be mutable",
             ast,
         )
-        .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
+        // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive, hence not stable.
         .with_fixes(fixes),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index fa3347aa12e..84fb467a5ce 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -22,6 +22,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
             "field is private",
             node,
         )
+        .stable()
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
@@ -32,6 +33,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
             "no such field",
             node,
         )
+        .stable()
         .with_fixes(fixes(ctx, d))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index ff1eeb0516a..35cefd23975 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -14,6 +14,7 @@ pub(crate) fn non_exhaustive_let(
         format!("non-exhaustive pattern: {}", d.uncovered_patterns),
         d.pat.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
index ccf51723418..68f2b196570 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
@@ -14,6 +14,7 @@ pub(crate) fn parenthesized_generic_args_without_fn_trait(
         "parenthesized type parameters may only be used with a `Fn` trait",
         d.args.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
index fe32c590492..6d33ae0cf9b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
@@ -28,6 +28,7 @@ pub(crate) fn private_assoc_item(
         ),
         d.expr_or_pat.map(Into::into),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 237a9b87871..5b4273a5a62 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -15,6 +15,7 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
         ),
         d.expr.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 6b786450026..dec7be8b742 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -31,6 +31,7 @@ pub(crate) fn remove_trailing_return(
             "replace return <expr>; with <expr>",
             display_range,
         )
+        .stable()
         .with_fixes(fixes(ctx, d)),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 8d717b9093b..7dc5b5b45e5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -36,7 +36,6 @@ pub(crate) fn remove_unnecessary_else(
             "remove unnecessary else block",
             display_range,
         )
-        .experimental()
         .with_fixes(fixes(ctx, d)),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 6b335c52de7..37ce5f583f9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -21,6 +21,7 @@ pub(crate) fn replace_filter_map_next_with_find_map(
         "replace filter_map(..).next() with find_map(..)",
         InFile::new(d.file, d.next_expr.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
index 19ee1caa3e6..dd142db8590 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
@@ -33,6 +33,7 @@ pub(crate) fn trait_impl_incorrect_safety(
             },
         ),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 2d7d78f5d7b..fa7ba90a756 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -29,6 +29,7 @@ pub(crate) fn trait_impl_missing_assoc_item(
             &|impl_| impl_.trait_().map(|t| t.syntax().text_range()),
         ),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
index 35dc9b0fac8..96911d4781b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
@@ -16,8 +16,6 @@ pub(crate) fn trait_impl_orphan(
             .to_owned(),
         InFile::new(d.file_id, d.impl_.into()),
     )
-    // Not yet checked for false positives
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index d5c4bcf768a..4327b12dce7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -61,6 +61,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
         format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
         ide_db::FileRange { file_id: file_id.file_id(ctx.sema.db), range },
     )
+    .stable()
     .with_fixes(quickfix_for_redundant_assoc_item(
         ctx,
         d,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 500c5de791d..5253734867e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -53,8 +53,8 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
         display_range,
     )
     .with_fixes(fixes(ctx, d));
-    if diag.fixes.is_none() {
-        diag.experimental = true;
+    if diag.fixes.is_some() {
+        diag.experimental = false;
     }
     diag
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index a933f1b4261..1915a88dd00 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -37,6 +37,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
     };
 
     Diagnostic::new(DiagnosticCode::RustcHardError("typed-hole"), message, display_range)
+        .stable()
         .with_fixes(fixes)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index d16bfb80024..f81d34377da 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn undeclared_label(
         format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
index 06f176f86f4..5627393f318 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
@@ -13,4 +13,5 @@ pub(crate) fn unimplemented_builtin_macro(
         "unimplemented built-in macro".to_owned(),
         d.node,
     )
+    .stable()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 47fa3059362..af9126c8933 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -2,7 +2,8 @@
 
 use std::iter;
 
-use hir::{DefMap, InFile, ModuleSource, db::DefDatabase};
+use hir::crate_def_map;
+use hir::{DefMap, InFile, ModuleSource};
 use ide_db::base_db::RootQueryDb;
 use ide_db::text_edit::TextEdit;
 use ide_db::{
@@ -101,7 +102,8 @@ fn fixes(
     // check crate roots, i.e. main.rs, lib.rs, ...
     let relevant_crates = db.relevant_crates(file_id);
     'crates: for &krate in &*relevant_crates {
-        let crate_def_map = ctx.sema.db.crate_def_map(krate);
+        // FIXME: This shouldnt need to access the crate def map directly
+        let crate_def_map = crate_def_map(ctx.sema.db, krate);
 
         let root_module = &crate_def_map[DefMap::ROOT];
         let Some(root_file_id) = root_module.origin.file_id() else { continue };
@@ -156,7 +158,7 @@ fn fixes(
     stack.pop();
     let relevant_crates = db.relevant_crates(parent_id);
     'crates: for &krate in relevant_crates.iter() {
-        let crate_def_map = ctx.sema.db.crate_def_map(krate);
+        let crate_def_map = crate_def_map(ctx.sema.db, krate);
         let Some((_, module)) = crate_def_map.modules().find(|(_, module)| {
             module.origin.file_id().map(|file_id| file_id.file_id(ctx.sema.db)) == Some(parent_id)
                 && !module.origin.is_inline()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
index bdff2417ca1..0c9e0d6ce44 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn unreachable_label(
         format!("use of unreachable label `{}`", name.display(ctx.sema.db, ctx.edition)),
         d.node.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
index 614057ab52b..4ae528bf9f2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_assoc_item(
         "no such associated item",
         d.expr_or_pat.map(Into::into),
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
index 4cd73d46d5f..7c3eacf7e3a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
@@ -13,6 +13,7 @@ pub(crate) fn unresolved_extern_crate(
         "unresolved extern crate",
         d.decl.map(|it| it.into()),
     )
+    .stable()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index a4f4813cf5b..0649c97f820 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -52,7 +52,6 @@ pub(crate) fn unresolved_field(
         }),
     )
     .with_fixes(fixes(ctx, d))
-    .experimental()
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
index 4f64dabeb52..801023dabd9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_ident(
         range.range = in_node_range + range.range.start();
     }
     Diagnostic::new(DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", range)
-        .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
index 67c7e76a3bc..0da535d11b4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
@@ -18,7 +18,6 @@ pub(crate) fn unresolved_import(
     // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
     // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
     // - proc macros and/or proc macro generated code
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 0d1c9775062..a87b8c42ac1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -16,7 +16,6 @@ pub(crate) fn unresolved_macro_call(
         format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db, ctx.edition)),
         display_range,
     )
-    .experimental()
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 7f07009dc56..00c2a8c4c46 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -47,7 +47,6 @@ pub(crate) fn unresolved_method(
         }),
     )
     .with_fixes(fixes(ctx, d))
-    .experimental()
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Vec<Assist>> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
index 599cabe3e4f..1a409d7e76a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
@@ -28,6 +28,7 @@ pub(crate) fn unresolved_module(
         },
         d.decl.map(|it| it.into()),
     )
+    .stable()
     .with_fixes(fixes(ctx, d))
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 77b1075ea53..e6bbff05f7e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -50,8 +50,7 @@ pub(crate) fn unused_variables(
                 ast.file_id.is_macro(),
                 ctx.edition,
             )
-        }))
-        .experimental(),
+        })),
     )
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 607721d611d..2af14ca949b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -182,7 +182,7 @@ impl Diagnostic {
                 DiagnosticCode::Ra(_, s) => s,
             },
             unused: false,
-            experimental: false,
+            experimental: true,
             fixes: None,
             main_node: None,
         }
@@ -198,8 +198,8 @@ impl Diagnostic {
             .with_main_node(node)
     }
 
-    fn experimental(mut self) -> Diagnostic {
-        self.experimental = true;
+    fn stable(mut self) -> Diagnostic {
+        self.experimental = false;
         self
     }
 
@@ -424,14 +424,11 @@ pub fn semantic_diagnostics(
             AnyDiagnostic::MacroExpansionParseError(d) => {
                 // FIXME: Point to the correct error span here, not just the macro-call name
                 res.extend(d.errors.iter().take(16).map(|err| {
-                    {
                         Diagnostic::new(
                             DiagnosticCode::SyntaxError,
                             format!("Syntax Error in Expansion: {err}"),
                             ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
                         )
-                    }
-                    .experimental()
                 }));
                 continue;
             },
@@ -485,12 +482,8 @@ pub fn semantic_diagnostics(
                 Some(it) => it,
                 None => continue,
             },
-            AnyDiagnostic::GenericArgsProhibited(d) => {
-                handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
-            }
-            AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => {
-                handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d)
-            }
+            AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d),
+            AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d),
             AnyDiagnostic::BadRtn(d) => handlers::bad_rtn::bad_rtn(&ctx, &d),
             AnyDiagnostic::IncorrectGenericsLen(d) => handlers::incorrect_generics_len::incorrect_generics_len(&ctx, &d),
             AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index f0247f32d7e..2c983287d89 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -5,17 +5,21 @@ mod tests;
 
 mod intra_doc_links;
 
+use std::ops::Range;
+
 use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
 use pulldown_cmark_to_cmark::{Options as CMarkOptions, cmark_resume_with_options};
 use stdx::format_to;
 use url::Url;
 
-use hir::{Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs, db::HirDatabase, sym};
+use hir::{
+    Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrsWithOwner, HasAttrs, db::HirDatabase, sym,
+};
 use ide_db::{
     RootDatabase,
     base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
     defs::{Definition, NameClass, NameRefClass},
-    documentation::{Documentation, HasDocs, docs_with_rangemap},
+    documentation::{DocsRangeMap, Documentation, HasDocs, docs_with_rangemap},
     helpers::pick_best_token,
 };
 use syntax::{
@@ -46,11 +50,17 @@ const MARKDOWN_OPTIONS: Options =
     Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS);
 
 /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
-pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String {
+pub(crate) fn rewrite_links(
+    db: &RootDatabase,
+    markdown: &str,
+    definition: Definition,
+    range_map: Option<DocsRangeMap>,
+) -> String {
     let mut cb = broken_link_clone_cb;
-    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
+    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb))
+        .into_offset_iter();
 
-    let doc = map_links(doc, |target, title| {
+    let doc = map_links(doc, |target, title, range| {
         // This check is imperfect, there's some overlap between valid intra-doc links
         // and valid URLs so we choose to be too eager to try to resolve what might be
         // a URL.
@@ -60,7 +70,16 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
             // Two possibilities:
             // * path-based links: `../../module/struct.MyStruct.html`
             // * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
-            if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
+            let text_range =
+                TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
+            let is_inner_doc = range_map
+                .as_ref()
+                .and_then(|range_map| range_map.map(text_range))
+                .map(|(_, attr_id)| attr_id.is_inner_attr())
+                .unwrap_or(false);
+            if let Some((target, title)) =
+                rewrite_intra_doc_link(db, definition, target, title, is_inner_doc)
+            {
                 (None, target, title)
             } else if let Some(target) = rewrite_url_link(db, definition, target) {
                 (Some(LinkType::Inline), target, title.to_owned())
@@ -195,22 +214,23 @@ pub(crate) fn resolve_doc_path_for_def(
     def: Definition,
     link: &str,
     ns: Option<hir::Namespace>,
+    is_inner_doc: bool,
 ) -> Option<Definition> {
     match def {
-        Definition::Module(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Crate(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Function(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Adt(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Variant(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Const(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Static(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Trait(it) => it.resolve_doc_path(db, link, ns),
-        Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns),
-        Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
-        Definition::Field(it) => it.resolve_doc_path(db, link, ns),
-        Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
-        Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
+        Definition::Module(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Adt(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Variant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Macro(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::Field(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::SelfType(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+        Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
         Definition::BuiltinAttr(_)
         | Definition::BuiltinType(_)
         | Definition::BuiltinLifetime(_)
@@ -289,31 +309,58 @@ impl DocCommentToken {
         let relative_comment_offset = offset - original_start - prefix_len;
 
         sema.descend_into_macros(doc_token).into_iter().find_map(|t| {
-            let (node, descended_prefix_len) = match_ast! {
+            let (node, descended_prefix_len, is_inner) = match_ast!{
                 match t {
-                    ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),
-                    ast::String(string) => (t.parent_ancestors().skip_while(|n| n.kind() != ATTR).nth(1)?, string.open_quote_text_range()?.len()),
+                    ast::Comment(comment) => {
+                        (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?, comment.is_inner())
+                    },
+                    ast::String(string) => {
+                        let attr = t.parent_ancestors().find_map(ast::Attr::cast)?;
+                        let attr_is_inner = attr.excl_token().map(|excl| excl.kind() == BANG).unwrap_or(false);
+                        (attr.syntax().parent()?, string.open_quote_text_range()?.len(), attr_is_inner)
+                    },
                     _ => return None,
                 }
             };
             let token_start = t.text_range().start();
             let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
-
-            let (attributes, def) = doc_attributes(sema, &node)?;
+            let (attributes, def) = Self::doc_attributes(sema, &node, is_inner)?;
             let (docs, doc_mapping) = docs_with_rangemap(sema.db, &attributes)?;
-            let (in_expansion_range, link, ns) =
+            let (in_expansion_range, link, ns, is_inner) =
                 extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
-                    let mapped = doc_mapping.map(range)?;
-                    (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns))
+                    let (mapped, idx) = doc_mapping.map(range)?;
+                    (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns, idx.is_inner_attr()))
                 })?;
             // get the relative range to the doc/attribute in the expansion
             let in_expansion_relative_range = in_expansion_range - descended_prefix_len - token_start;
             // Apply relative range to the original input comment
             let absolute_range = in_expansion_relative_range + original_start + prefix_len;
-            let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
+            let def = resolve_doc_path_for_def(sema.db, def, &link, ns, is_inner)?;
             cb(def, node, absolute_range)
         })
     }
+
+    /// When we hover a inner doc item, this find a attached definition.
+    /// ```
+    /// // node == ITEM_LIST
+    /// // node.parent == EXPR_BLOCK
+    /// // node.parent().parent() == FN
+    /// fn f() {
+    ///    //! [`S$0`]
+    /// }
+    /// ```
+    fn doc_attributes(
+        sema: &Semantics<'_, RootDatabase>,
+        node: &SyntaxNode,
+        is_inner_doc: bool,
+    ) -> Option<(AttrsWithOwner, Definition)> {
+        if is_inner_doc && node.kind() != SOURCE_FILE {
+            let parent = node.parent()?;
+            doc_attributes(sema, &parent).or(doc_attributes(sema, &parent.parent()?))
+        } else {
+            doc_attributes(sema, node)
+        }
+    }
 }
 
 fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>)> {
@@ -369,6 +416,7 @@ fn rewrite_intra_doc_link(
     def: Definition,
     target: &str,
     title: &str,
+    is_inner_doc: bool,
 ) -> Option<(String, String)> {
     let (link, ns) = parse_intra_doc_link(target);
 
@@ -377,7 +425,7 @@ fn rewrite_intra_doc_link(
         None => (link, None),
     };
 
-    let resolved = resolve_doc_path_for_def(db, def, link, ns)?;
+    let resolved = resolve_doc_path_for_def(db, def, link, ns, is_inner_doc)?;
     let mut url = get_doc_base_urls(db, resolved, None, None).0?;
 
     let (_, file, frag) = filename_and_frag_for_def(db, resolved)?;
@@ -421,8 +469,8 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
 
 /// Rewrites a markdown document, applying 'callback' to each link.
 fn map_links<'e>(
-    events: impl Iterator<Item = Event<'e>>,
-    callback: impl Fn(&str, &str) -> (Option<LinkType>, String, String),
+    events: impl Iterator<Item = (Event<'e>, Range<usize>)>,
+    callback: impl Fn(&str, &str, Range<usize>) -> (Option<LinkType>, String, String),
 ) -> impl Iterator<Item = Event<'e>> {
     let mut in_link = false;
     // holds the origin link target on start event and the rewritten one on end event
@@ -432,7 +480,7 @@ fn map_links<'e>(
     // `Shortcut` type parsed from Start/End tags doesn't make sense for url links
     let mut end_link_type: Option<LinkType> = None;
 
-    events.map(move |evt| match evt {
+    events.map(move |(evt, range)| match evt {
         Event::Start(Tag::Link(link_type, ref target, _)) => {
             in_link = true;
             end_link_target = Some(target.clone());
@@ -449,7 +497,7 @@ fn map_links<'e>(
         }
         Event::Text(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s);
+                callback(&end_link_target.take().unwrap(), &s, range);
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
@@ -458,7 +506,7 @@ fn map_links<'e>(
         }
         Event::Code(s) if in_link => {
             let (link_type, link_target_s, link_name) =
-                callback(&end_link_target.take().unwrap(), &s);
+                callback(&end_link_target.take().unwrap(), &s, range);
             end_link_target = Some(CowStr::Boxed(link_target_s.into()));
             if !matches!(end_link_type, Some(LinkType::Autolink)) {
                 end_link_type = link_type;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 91785be8d8b..6af156fa668 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -5,7 +5,7 @@ use hir::Semantics;
 use ide_db::{
     FilePosition, FileRange, RootDatabase,
     defs::Definition,
-    documentation::{Documentation, HasDocs},
+    documentation::{DocsRangeMap, Documentation, HasDocs},
 };
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxNode, ast, match_ast};
@@ -45,8 +45,8 @@ fn check_external_docs(
 fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
     let sema = &Semantics::new(&analysis.db);
-    let (cursor_def, docs) = def_under_cursor(sema, &position);
-    let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
+    let (cursor_def, docs, range) = def_under_cursor(sema, &position);
+    let res = rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range));
     expect.assert_eq(&res)
 }
 
@@ -56,12 +56,14 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
     let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
     expected.sort_by_key(key_fn);
     let sema = &Semantics::new(&analysis.db);
-    let (cursor_def, docs) = def_under_cursor(sema, &position);
+    let (cursor_def, docs, range) = def_under_cursor(sema, &position);
     let defs = extract_definitions_from_docs(&docs);
     let actual: Vec<_> = defs
         .into_iter()
-        .flat_map(|(_, link, ns)| {
-            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
+        .flat_map(|(text_range, link, ns)| {
+            let attr = range.map(text_range);
+            let is_inner_attr = attr.map(|(_file, attr)| attr.is_inner_attr()).unwrap_or(false);
+            let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr)
                 .unwrap_or_else(|| panic!("Failed to resolve {link}"));
             def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link))
         })
@@ -78,7 +80,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
 fn def_under_cursor(
     sema: &Semantics<'_, RootDatabase>,
     position: &FilePosition,
-) -> (Definition, Documentation) {
+) -> (Definition, Documentation, DocsRangeMap) {
     let (docs, def) = sema
         .parse_guess_edition(position.file_id)
         .syntax()
@@ -89,31 +91,31 @@ fn def_under_cursor(
         .find_map(|it| node_to_def(sema, &it))
         .expect("no def found")
         .unwrap();
-    let docs = docs.expect("no docs found for cursor def");
-    (def, docs)
+    let (docs, range) = docs.expect("no docs found for cursor def");
+    (def, docs, range)
 }
 
 fn node_to_def(
     sema: &Semantics<'_, RootDatabase>,
     node: &SyntaxNode,
-) -> Option<Option<(Option<Documentation>, Definition)>> {
+) -> Option<Option<(Option<(Documentation, DocsRangeMap)>, Definition)>> {
     Some(match_ast! {
         match node {
-            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
-            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
-            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))),
-            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
-            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
-            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
-            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))),
-            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))),
-            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))),
-            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))),
-            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))),
-            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))),
-            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
-            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
-            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))),
+            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+            ast::Module(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Function(def))),
+            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
+            ast::Union(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Union(def)))),
+            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
+            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Variant(def))),
+            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Trait(def))),
+            ast::Static(it)      => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Static(def))),
+            ast::Const(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Const(def))),
+            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::TypeAlias(def))),
+            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::SelfType(def))),
+            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Macro(def))),
             // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
             _ => return None,
         }
@@ -576,6 +578,40 @@ struct S$0(i32);
 }
 
 #[test]
+fn doc_links_module() {
+    check_doc_links(
+        r#"
+/// [`M`]
+/// [`M::f`]
+mod M$0 {
+  //^ M
+  #![doc = "inner_item[`S`]"]
+
+    pub fn f() {}
+         //^ M::f
+    pub struct S;
+             //^ S
+}
+"#,
+    );
+
+    check_doc_links(
+        r#"
+mod M$0 {
+  //^ super::M
+    //! [`super::M`]
+    //! [`super::M::f`]
+    //! [`super::M::S`]
+    pub fn f() {}
+         //^ super::M::f
+    pub struct S;
+             //^ super::M::S
+}
+"#,
+    );
+}
+
+#[test]
 fn rewrite_html_root_url() {
     check_rewrite(
         r#"
@@ -691,6 +727,29 @@ fn rewrite_intra_doc_link_with_anchor() {
 }
 
 #[test]
+fn rewrite_module() {
+    check_rewrite(
+        r#"
+//- /main.rs crate:foo
+/// [Foo]
+pub mod $0Foo{
+};
+"#,
+        expect![[r#"[Foo](https://docs.rs/foo/*/foo/Foo/index.html)"#]],
+    );
+
+    check_rewrite(
+        r#"
+//- /main.rs crate:foo
+pub mod $0Foo{
+    //! [super::Foo]
+};
+"#,
+        expect![[r#"[super::Foo](https://docs.rs/foo/*/foo/Foo/index.html)"#]],
+    );
+}
+
+#[test]
 fn rewrite_intra_doc_link_to_associated_item() {
     check_rewrite(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index b894e857522..c60ca3562f6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -1923,6 +1923,74 @@ pub fn foo() { }
     }
 
     #[test]
+    fn goto_def_for_intra_doc_link_outer_same_file() {
+        check(
+            r#"
+/// [`S$0`]
+mod m {
+    //! [`super::S`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+/// [`S$0`]
+mod m {}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+/// [`S$0`]
+fn f() {
+    //! [`S`]
+}
+struct S;
+     //^
+            "#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_intra_doc_link_inner_same_file() {
+        check(
+            r#"
+/// [`S`]
+mod m {
+    //! [`super::S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+mod m {
+    //! [`super::S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+
+        check(
+            r#"
+fn f() {
+    //! [`S$0`]
+}
+struct S;
+     //^
+            "#,
+        );
+    }
+
+    #[test]
     fn goto_def_for_intra_doc_link_inner() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 80624eeae80..fb8dbcfc735 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -89,6 +89,9 @@ pub(crate) fn highlight_related(
         T![break] | T![loop] | T![while] | T![continue] if config.break_points => {
             highlight_break_points(sema, token).remove(&file_id)
         }
+        T![unsafe] if token.parent().and_then(ast::BlockExpr::cast).is_some() => {
+            highlight_unsafe_points(sema, token).remove(&file_id)
+        }
         T![|] if config.closure_captures => {
             highlight_closure_captures(sema, token, file_id, span_file_id.file_id())
         }
@@ -706,6 +709,44 @@ impl<'a> WalkExpandedExprCtx<'a> {
     }
 }
 
+pub(crate) fn highlight_unsafe_points(
+    sema: &Semantics<'_, RootDatabase>,
+    token: SyntaxToken,
+) -> FxHashMap<EditionedFileId, Vec<HighlightedRange>> {
+    fn hl(
+        sema: &Semantics<'_, RootDatabase>,
+        unsafe_token: &SyntaxToken,
+        block_expr: Option<ast::BlockExpr>,
+    ) -> Option<FxHashMap<EditionedFileId, Vec<HighlightedRange>>> {
+        let mut highlights: FxHashMap<EditionedFileId, Vec<_>> = FxHashMap::default();
+
+        let mut push_to_highlights = |file_id, range| {
+            if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) {
+                let hrange = HighlightedRange { category: ReferenceCategory::empty(), range };
+                highlights.entry(file_id).or_default().push(hrange);
+            }
+        };
+
+        // highlight unsafe keyword itself
+        let unsafe_token_file_id = sema.hir_file_for(&unsafe_token.parent()?);
+        push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range()));
+
+        // highlight unsafe operations
+        if let Some(block) = block_expr {
+            if let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) {
+                let unsafe_ops = sema.get_unsafe_ops(body);
+                for unsafe_op in unsafe_ops {
+                    push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range()));
+                }
+            }
+        }
+
+        Some(highlights)
+    }
+
+    hl(sema, &token, token.parent().and_then(ast::BlockExpr::cast)).unwrap_or_default()
+}
+
 #[cfg(test)]
 mod tests {
     use itertools::Itertools;
@@ -755,6 +796,32 @@ mod tests {
     }
 
     #[test]
+    fn test_hl_unsafe_block() {
+        check(
+            r#"
+fn foo() {
+    unsafe fn this_is_unsafe_function() {}
+
+    unsa$0fe {
+  //^^^^^^
+        let raw_ptr = &42 as *const i32;
+        let val = *raw_ptr;
+                //^^^^^^^^
+
+        let mut_ptr = &mut 5 as *mut i32;
+        *mut_ptr = 10;
+      //^^^^^^^^
+
+        this_is_unsafe_function();
+      //^^^^^^^^^^^^^^^^^^^^^^^^^
+    }
+
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_hl_tuple_fields() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 075afcec019..873e31b4a33 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -456,7 +456,7 @@ pub(crate) fn hover_for_definition(
     let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
     let subst_types = subst.map(|subst| subst.types(db));
 
-    let markup = render::definition(
+    let (markup, range_map) = render::definition(
         sema.db,
         def,
         famous_defs.as_ref(),
@@ -469,7 +469,7 @@ pub(crate) fn hover_for_definition(
         display_target,
     );
     HoverResult {
-        markup: render::process_markup(sema.db, def, &markup, config),
+        markup: render::process_markup(sema.db, def, &markup, range_map, config),
         actions: [
             show_fn_references_action(sema.db, def),
             show_implementations_action(sema.db, def),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 69b83f3b12d..ad720c8a627 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -11,7 +11,7 @@ use hir::{
 use ide_db::{
     RootDatabase,
     defs::Definition,
-    documentation::HasDocs,
+    documentation::{DocsRangeMap, HasDocs},
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
     syntax_helpers::prettify_macro_expansion,
@@ -21,7 +21,7 @@ use rustc_apfloat::{
     Float,
     ieee::{Half as f16, Quad as f128},
 };
-use span::Edition;
+use span::{Edition, TextSize};
 use stdx::format_to;
 use syntax::{AstNode, AstToken, Direction, SyntaxToken, T, algo, ast, match_ast};
 
@@ -276,13 +276,10 @@ pub(super) fn keyword(
         keyword_hints(sema, token, parent, edition, display_target);
 
     let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?;
-    let docs = doc_owner.docs(sema.db)?;
-    let markup = process_markup(
-        sema.db,
-        Definition::Module(doc_owner),
-        &markup(Some(docs.into()), description, None, None, String::new()),
-        config,
-    );
+    let (docs, range_map) = doc_owner.docs_with_rangemap(sema.db)?;
+    let (markup, range_map) =
+        markup(Some(docs.into()), Some(range_map), description, None, None, String::new());
+    let markup = process_markup(sema.db, Definition::Module(doc_owner), &markup, range_map, config);
     Some(HoverResult { markup, actions })
 }
 
@@ -371,11 +368,15 @@ pub(super) fn process_markup(
     db: &RootDatabase,
     def: Definition,
     markup: &Markup,
+    markup_range_map: Option<DocsRangeMap>,
     config: &HoverConfig,
 ) -> Markup {
     let markup = markup.as_str();
-    let markup =
-        if config.links_in_hover { rewrite_links(db, markup, def) } else { remove_links(markup) };
+    let markup = if config.links_in_hover {
+        rewrite_links(db, markup, def, markup_range_map)
+    } else {
+        remove_links(markup)
+    };
     Markup::from(markup)
 }
 
@@ -482,7 +483,7 @@ pub(super) fn definition(
     config: &HoverConfig,
     edition: Edition,
     display_target: DisplayTarget,
-) -> Markup {
+) -> (Markup, Option<DocsRangeMap>) {
     let mod_path = definition_path(db, &def, edition);
     let label = match def {
         Definition::Trait(trait_) => trait_
@@ -518,7 +519,12 @@ pub(super) fn definition(
         }
         _ => def.label(db, display_target),
     };
-    let docs = def.docs(db, famous_defs, display_target);
+    let (docs, range_map) =
+        if let Some((docs, doc_range)) = def.docs_with_rangemap(db, famous_defs, display_target) {
+            (Some(docs), doc_range)
+        } else {
+            (None, None)
+        };
     let value = || match def {
         Definition::Variant(it) => {
             if !it.parent_enum(db).is_data_carrying(db) {
@@ -807,6 +813,7 @@ pub(super) fn definition(
 
     markup(
         docs.map(Into::into),
+        range_map,
         desc,
         extra.is_empty().not().then_some(extra),
         mod_path,
@@ -1083,11 +1090,12 @@ fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Op
 
 fn markup(
     docs: Option<String>,
+    range_map: Option<DocsRangeMap>,
     rust: String,
     extra: Option<String>,
     mod_path: Option<String>,
     subst_types: String,
-) -> Markup {
+) -> (Markup, Option<DocsRangeMap>) {
     let mut buf = String::new();
 
     if let Some(mod_path) = mod_path {
@@ -1106,9 +1114,15 @@ fn markup(
     }
 
     if let Some(doc) = docs {
-        format_to!(buf, "\n___\n\n{}", doc);
+        format_to!(buf, "\n___\n\n");
+        let offset = TextSize::new(buf.len() as u32);
+        let buf_range_map = range_map.map(|range_map| range_map.shift_docstring_line_range(offset));
+        format_to!(buf, "{}", doc);
+
+        (buf.into(), buf_range_map)
+    } else {
+        (buf.into(), None)
     }
-    buf.into()
 }
 
 fn find_std_module(
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 7b7eef9d579..06ca24c3ec3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -7375,6 +7375,128 @@ pub struct Foo(i32);
 }
 
 #[test]
+fn hover_intra_inner_attr() {
+    check(
+        r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo {
+    //! inner comment for [`Foo$0`]
+    #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub fn Foo()
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+        "#]],
+    );
+
+    check(
+        r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+    //! inner comment for [`super::Foo$0`]
+    #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`super::Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub mod Foo
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+        "#]],
+    );
+}
+
+#[test]
+fn hover_intra_outer_attr() {
+    check(
+        r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo() {
+    //! inner comment for [`Foo`]
+    #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub fn Foo()
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+            Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+        "#]],
+    );
+
+    check(
+        r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+    //! inner comment for [`super::Foo`]
+    #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+        expect![[r#"
+            *[`Foo`]*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub mod Foo
+            ```
+
+            ---
+
+            outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+            Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+        "#]],
+    );
+}
+
+#[test]
 fn hover_intra_generics() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index aa525a86123..d649dffbd90 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@ use std::panic::{AssertUnwindSafe, UnwindSafe};
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::{ChangeWithProcMacros, EditionedFileId, sym};
+use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
 use ide_db::{
     FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
@@ -627,7 +627,7 @@ impl Analysis {
 
     /// Returns true if this crate has `no_std` or `no_core` specified.
     pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable<bool> {
-        self.with_db(|db| hir::db::DefDatabase::crate_def_map(db, crate_id).is_no_std())
+        self.with_db(|db| crate_def_map(db, crate_id).is_no_std())
     }
 
     /// Returns the root file of the given crate.
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 6dc01c45063..50219cee57d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,4 +1,4 @@
-use hir::{Semantics, db::DefDatabase};
+use hir::{Semantics, crate_def_map};
 use ide_db::{
     FileId, FilePosition, RootDatabase,
     base_db::{Crate, RootQueryDb},
@@ -58,7 +58,7 @@ pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
         .iter()
         .copied()
         .filter(|&crate_id| {
-            db.crate_def_map(crate_id).modules_for_file(db, file_id).next().is_some()
+            crate_def_map(db, crate_id).modules_for_file(db, file_id).next().is_some()
         })
         .sorted()
         .collect()
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 0998e14c87b..7f5c2c1ec84 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -129,11 +129,18 @@ pub(super) fn doc_comment(
         extract_definitions_from_docs(&docs)
             .into_iter()
             .filter_map(|(range, link, ns)| {
-                doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then(
-                    |InFile { value: mapped_range, .. }| {
-                        Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
-                    },
-                )
+                doc_mapping
+                    .map(range)
+                    .filter(|(mapping, _)| mapping.file_id == src_file_id)
+                    .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+                        Some(mapped_range).zip(resolve_doc_path_for_def(
+                            sema.db,
+                            def,
+                            &link,
+                            ns,
+                            attr_id.is_inner_attr(),
+                        ))
+                    })
             })
             .for_each(|(range, def)| {
                 hl.add(HlRange {
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 2686a75c7c8..30e2d5416cf 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -512,10 +512,6 @@ impl ProcMacroExpander for Expander {
             Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
         }
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().downcast_ref::<Self>().is_some_and(|other| self == other)
-    }
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
index a5672e4e050..3369dfff281 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
@@ -356,3 +356,120 @@ fn expr_2021() {
             ;"#]],
     );
 }
+
+#[test]
+fn minus_belongs_to_literal() {
+    let decl = r#"
+(-1) => {-1};
+(- 2) => {- 2};
+(- 3.0) => {- 3.0};
+(@$lit:literal) => {$lit}
+"#;
+    let check = |args, expect| check(Edition::CURRENT, Edition::CURRENT, decl, args, expect);
+    check(
+        "-1",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+              PUNCH   - [alone] 0:0@10..11#ROOT2024
+              LITERAL Integer 1 0:0@11..12#ROOT2024
+
+            -1"#]],
+    );
+    check(
+        "- 1",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+              PUNCH   - [alone] 0:0@10..11#ROOT2024
+              LITERAL Integer 1 0:0@11..12#ROOT2024
+
+            -1"#]],
+    );
+    check(
+        "-2",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+              PUNCH   - [alone] 0:0@25..26#ROOT2024
+              LITERAL Integer 2 0:0@27..28#ROOT2024
+
+            -2"#]],
+    );
+    check(
+        "- 2",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+              PUNCH   - [alone] 0:0@25..26#ROOT2024
+              LITERAL Integer 2 0:0@27..28#ROOT2024
+
+            -2"#]],
+    );
+    check(
+        "-3.0",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
+              PUNCH   - [alone] 0:0@43..44#ROOT2024
+              LITERAL Float 3.0 0:0@45..48#ROOT2024
+
+            -3.0"#]],
+    );
+    check(
+        "- 3.0",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
+              PUNCH   - [alone] 0:0@43..44#ROOT2024
+              LITERAL Float 3.0 0:0@45..48#ROOT2024
+
+            -3.0"#]],
+    );
+    check(
+        "@1",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+              LITERAL Integer 1 1:0@1..2#ROOT2024
+
+            1"#]],
+    );
+    check(
+        "@-1",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+              PUNCH   - [alone] 1:0@1..2#ROOT2024
+              LITERAL Integer 1 1:0@2..3#ROOT2024
+
+            -1"#]],
+    );
+    check(
+        "@1.0",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
+              LITERAL Float 1.0 1:0@1..4#ROOT2024
+
+            1.0"#]],
+    );
+    check(
+        "@-1.0",
+        expect![[r#"
+            SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
+              PUNCH   - [alone] 1:0@1..2#ROOT2024
+              LITERAL Float 1.0 1:0@2..5#ROOT2024
+
+            -1.0"#]],
+    );
+    check(
+        "@--1.0",
+        expect![[r#"
+            ExpandError {
+                inner: (
+                    1:0@1..2#ROOT2024,
+                    BindingError(
+                        "expected literal",
+                    ),
+                ),
+            }
+
+            SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024
+              PUNCH   - [joint] 1:0@1..2#ROOT2024
+              PUNCH   - [alone] 1:0@2..3#ROOT2024
+
+            --"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 5faf6fc2759..8cc332d4633 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -381,10 +381,14 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
             op.complete(p, ASM_REG_OPERAND);
             op_n.complete(p, ASM_OPERAND_NAMED);
         } else if p.eat_contextual_kw(T![label]) {
+            // test asm_label
+            // fn foo() {
+            //     builtin#asm("", label {});
+            // }
             dir_spec.abandon(p);
             block_expr(p);
-            op.complete(p, ASM_OPERAND_NAMED);
-            op_n.complete(p, ASM_LABEL);
+            op.complete(p, ASM_LABEL);
+            op_n.complete(p, ASM_OPERAND_NAMED);
         } else if p.eat(T![const]) {
             dir_spec.abandon(p);
             expr(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index 0a5c16dc4c4..0fa9a264545 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -179,7 +179,10 @@ impl<'a> Converter<'a> {
                     COMMENT
                 }
 
-                rustc_lexer::TokenKind::Frontmatter  { has_invalid_preceding_whitespace, invalid_infostring } => {
+                rustc_lexer::TokenKind::Frontmatter {
+                    has_invalid_preceding_whitespace,
+                    invalid_infostring,
+                } => {
                     if *has_invalid_preceding_whitespace {
                         err = "invalid preceding whitespace for frontmatter opening"
                     } else if *invalid_infostring {
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 24db9478ee5..030d8e0f04d 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -21,6 +21,8 @@ mod ok {
     #[test]
     fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); }
     #[test]
+    fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); }
+    #[test]
     fn assoc_const_eq() {
         run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs");
     }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast
new file mode 100644
index 00000000000..38999c9cd34
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          ASM_EXPR
+            BUILTIN_KW "builtin"
+            POUND "#"
+            ASM_KW "asm"
+            L_PAREN "("
+            LITERAL
+              STRING "\"\""
+            COMMA ","
+            WHITESPACE " "
+            ASM_OPERAND_NAMED
+              ASM_LABEL
+                LABEL_KW "label"
+                WHITESPACE " "
+                BLOCK_EXPR
+                  STMT_LIST
+                    L_CURLY "{"
+                    R_CURLY "}"
+            R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs
new file mode 100644
index 00000000000..996c1c8477b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs
@@ -0,0 +1,3 @@
+fn foo() {
+    builtin#asm("", label {});
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
index dfdbb4c95fc..6820e4b3353 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
@@ -31,12 +31,17 @@ pub fn fn_like_mk_literals(_args: TokenStream) -> TokenStream {
         TokenTree::from(Literal::byte_string(b"byte_string")),
         TokenTree::from(Literal::character('c')),
         TokenTree::from(Literal::string("string")),
+        TokenTree::from(Literal::c_string(c"cstring")),
         // as of 2022-07-21, there's no method on `Literal` to build a raw
         // string or a raw byte string
         TokenTree::from(Literal::f64_suffixed(3.14)),
+        TokenTree::from(Literal::f64_suffixed(-3.14)),
         TokenTree::from(Literal::f64_unsuffixed(3.14)),
+        TokenTree::from(Literal::f64_unsuffixed(-3.14)),
         TokenTree::from(Literal::i64_suffixed(123)),
+        TokenTree::from(Literal::i64_suffixed(-123)),
         TokenTree::from(Literal::i64_unsuffixed(123)),
+        TokenTree::from(Literal::i64_unsuffixed(-123)),
     ];
     TokenStream::from_iter(trees)
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
index 3d999421794..11dbd920091 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
@@ -16,9 +16,8 @@ mod token_stream;
 pub use token_stream::TokenStream;
 
 pub mod rust_analyzer_span;
-// mod symbol;
 pub mod token_id;
-// pub use symbol::*;
+
 use tt::Spacing;
 
 #[derive(Clone)]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 47555a5db2f..64b40e7b943 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -168,16 +168,38 @@ impl server::TokenStream for RaSpanServer {
             }
 
             bridge::TokenTree::Literal(literal) => {
-                let literal = tt::Literal {
-                    symbol: literal.symbol,
-                    suffix: literal.suffix,
-                    span: literal.span,
-                    kind: literal_kind_to_internal(literal.kind),
-                };
-
-                let leaf: tt::Leaf = tt::Leaf::from(literal);
-                let tree = tt::TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
+                let token_trees =
+                    if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
+                        let punct = tt::Punct {
+                            spacing: tt::Spacing::Alone,
+                            span: literal.span,
+                            char: '-' as char,
+                        };
+                        let leaf: tt::Leaf = tt::Leaf::from(punct);
+                        let minus_tree = tt::TokenTree::from(leaf);
+
+                        let literal = tt::Literal {
+                            symbol: Symbol::intern(symbol),
+                            suffix: literal.suffix,
+                            span: literal.span,
+                            kind: literal_kind_to_internal(literal.kind),
+                        };
+                        let leaf: tt::Leaf = tt::Leaf::from(literal);
+                        let tree = tt::TokenTree::from(leaf);
+                        vec![minus_tree, tree]
+                    } else {
+                        let literal = tt::Literal {
+                            symbol: literal.symbol,
+                            suffix: literal.suffix,
+                            span: literal.span,
+                            kind: literal_kind_to_internal(literal.kind),
+                        };
+
+                        let leaf: tt::Leaf = tt::Leaf::from(literal);
+                        let tree = tt::TokenTree::from(leaf);
+                        vec![tree]
+                    };
+                TokenStream { token_trees }
             }
 
             bridge::TokenTree::Punct(p) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs
deleted file mode 100644
index 6863ce95997..00000000000
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-//! Symbol interner for proc-macro-srv
-
-use std::{cell::RefCell, collections::HashMap, thread::LocalKey};
-
-thread_local! {
-    pub(crate) static SYMBOL_INTERNER: RefCell<SymbolInterner> = Default::default();
-}
-
-// ID for an interned symbol.
-#[derive(Hash, Eq, PartialEq, Copy, Clone)]
-pub struct Symbol(u32);
-
-pub(crate) type SymbolInternerRef = &'static LocalKey<RefCell<SymbolInterner>>;
-
-impl Symbol {
-    pub(super) fn intern(interner: SymbolInternerRef, data: &str) -> Symbol {
-        interner.with(|i| i.borrow_mut().intern(data))
-    }
-
-    pub(super) fn text(&self, interner: SymbolInternerRef) -> SmolStr {
-        interner.with(|i| i.borrow().get(self).clone())
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct SymbolInterner {
-    idents: HashMap<SmolStr, u32>,
-    ident_data: Vec<SmolStr>,
-}
-
-impl SymbolInterner {
-    fn intern(&mut self, data: &str) -> Symbol {
-        if let Some(index) = self.idents.get(data) {
-            return Symbol(*index);
-        }
-
-        let index = self.idents.len() as u32;
-        let data = SmolStr::from(data);
-        self.ident_data.push(data.clone());
-        self.idents.insert(data, index);
-        Symbol(index)
-    }
-
-    fn get(&self, sym: &Symbol) -> &SmolStr {
-        &self.ident_data[sym.0 as usize]
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index c002be4be6f..24a67bf45c8 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -153,16 +153,38 @@ impl server::TokenStream for TokenIdServer {
             }
 
             bridge::TokenTree::Literal(literal) => {
-                let literal = Literal {
-                    symbol: literal.symbol,
-                    suffix: literal.suffix,
-                    span: literal.span,
-                    kind: literal_kind_to_internal(literal.kind),
-                };
-
-                let leaf = tt::Leaf::from(literal);
-                let tree = TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
+                let token_trees =
+                    if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
+                        let punct = tt::Punct {
+                            spacing: tt::Spacing::Alone,
+                            span: literal.span,
+                            char: '-' as char,
+                        };
+                        let leaf: tt::Leaf = tt::Leaf::from(punct);
+                        let minus_tree = tt::TokenTree::from(leaf);
+
+                        let literal = Literal {
+                            symbol: Symbol::intern(symbol),
+                            suffix: literal.suffix,
+                            span: literal.span,
+                            kind: literal_kind_to_internal(literal.kind),
+                        };
+                        let leaf: tt::Leaf = tt::Leaf::from(literal);
+                        let tree = tt::TokenTree::from(leaf);
+                        vec![minus_tree, tree]
+                    } else {
+                        let literal = Literal {
+                            symbol: literal.symbol,
+                            suffix: literal.suffix,
+                            span: literal.span,
+                            kind: literal_kind_to_internal(literal.kind),
+                        };
+
+                        let leaf: tt::Leaf = tt::Leaf::from(literal);
+                        let tree = tt::TokenTree::from(leaf);
+                        vec![tree]
+                    };
+                TokenStream { token_trees }
             }
 
             bridge::TokenTree::Punct(p) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
index 4946a4f2a62..072557913c2 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
@@ -68,6 +68,11 @@ impl<S: Copy> TokenStream<S> {
                         span: ident.span,
                     }))
                 }
+                // Note, we do not have to assemble our `-` punct and literal split into a single
+                // negative bridge literal here. As the proc-macro docs state
+                // > Literals created from negative numbers might not survive round-trips through
+                // > TokenStream or strings and may be broken into two tokens (- and positive
+                // > literal).
                 tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                     result.push(bridge::TokenTree::Literal(bridge::Literal {
                         span: lit.span,
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index a81fea7bec6..3868fee40fb 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -11,8 +11,24 @@ fn test_derive_empty() {
     assert_expand(
         "DeriveEmpty",
         r#"struct S;"#,
-        expect!["SUBTREE $$ 1 1"],
-        expect!["SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"],
+        expect![[r#"
+            SUBTREE $$ 1 1
+              IDENT   struct 1
+              IDENT   S 1
+              PUNCH   ; [alone] 1
+
+
+
+            SUBTREE $$ 1 1"#]],
+        expect![[r#"
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   struct 42:2@0..6#ROOT2024
+              IDENT   S 42:2@7..8#ROOT2024
+              PUNCH   ; [alone] 42:2@8..9#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"#]],
     );
 }
 
@@ -23,6 +39,13 @@ fn test_derive_error() {
         r#"struct S;"#,
         expect![[r#"
             SUBTREE $$ 1 1
+              IDENT   struct 1
+              IDENT   S 1
+              PUNCH   ; [alone] 1
+
+
+
+            SUBTREE $$ 1 1
               IDENT   compile_error 1
               PUNCH   ! [alone] 1
               SUBTREE () 1 1
@@ -30,6 +53,13 @@ fn test_derive_error() {
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   struct 42:2@0..6#ROOT2024
+              IDENT   S 42:2@7..8#ROOT2024
+              PUNCH   ; [alone] 42:2@8..9#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   compile_error 42:2@0..100#ROOT2024
               PUNCH   ! [alone] 42:2@0..100#ROOT2024
               SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -51,6 +81,17 @@ fn test_fn_like_macro_noop() {
               PUNCH   , [alone] 1
               LITERAL Integer 1 1
               PUNCH   , [alone] 1
+              SUBTREE [] 1 1
+
+
+
+            SUBTREE $$ 1 1
+              IDENT   ident 1
+              PUNCH   , [alone] 1
+              LITERAL Integer 0 1
+              PUNCH   , [alone] 1
+              LITERAL Integer 1 1
+              PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -60,6 +101,17 @@ fn test_fn_like_macro_noop() {
               PUNCH   , [alone] 42:2@8..9#ROOT2024
               LITERAL Integer 1 42:2@10..11#ROOT2024
               PUNCH   , [alone] 42:2@11..12#ROOT2024
+              SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   ident 42:2@0..5#ROOT2024
+              PUNCH   , [alone] 42:2@5..6#ROOT2024
+              LITERAL Integer 0 42:2@7..8#ROOT2024
+              PUNCH   , [alone] 42:2@8..9#ROOT2024
+              LITERAL Integer 1 42:2@10..11#ROOT2024
+              PUNCH   , [alone] 42:2@11..12#ROOT2024
               SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024"#]],
     );
 }
@@ -73,11 +125,25 @@ fn test_fn_like_macro_clone_ident_subtree() {
             SUBTREE $$ 1 1
               IDENT   ident 1
               PUNCH   , [alone] 1
+              SUBTREE [] 1 1
+
+
+
+            SUBTREE $$ 1 1
+              IDENT   ident 1
+              PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   ident 42:2@0..5#ROOT2024
               PUNCH   , [alone] 42:2@5..6#ROOT2024
+              SUBTREE [] 42:2@7..8#ROOT2024 42:2@8..9#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   ident 42:2@0..5#ROOT2024
+              PUNCH   , [alone] 42:2@5..6#ROOT2024
               SUBTREE [] 42:2@7..8#ROOT2024 42:2@7..8#ROOT2024"#]],
     );
 }
@@ -89,9 +155,19 @@ fn test_fn_like_macro_clone_raw_ident() {
         "r#async",
         expect![[r#"
             SUBTREE $$ 1 1
+              IDENT   r#async 1
+
+
+
+            SUBTREE $$ 1 1
               IDENT   r#async 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   r#async 42:2@0..7#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   r#async 42:2@0..7#ROOT2024"#]],
     );
 }
@@ -103,9 +179,21 @@ fn test_fn_like_fn_like_span_join() {
         "foo     bar",
         expect![[r#"
             SUBTREE $$ 1 1
+              IDENT   foo 1
+              IDENT   bar 1
+
+
+
+            SUBTREE $$ 1 1
               IDENT   r#joined 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   foo 42:2@0..3#ROOT2024
+              IDENT   bar 42:2@8..11#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   r#joined 42:2@0..11#ROOT2024"#]],
     );
 }
@@ -117,11 +205,25 @@ fn test_fn_like_fn_like_span_ops() {
         "set_def_site resolved_at_def_site start_span",
         expect![[r#"
             SUBTREE $$ 1 1
+              IDENT   set_def_site 1
+              IDENT   resolved_at_def_site 1
+              IDENT   start_span 1
+
+
+
+            SUBTREE $$ 1 1
               IDENT   set_def_site 0
               IDENT   resolved_at_def_site 1
               IDENT   start_span 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   set_def_site 42:2@0..12#ROOT2024
+              IDENT   resolved_at_def_site 42:2@13..33#ROOT2024
+              IDENT   start_span 42:2@34..44#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   set_def_site 41:1@0..150#ROOT2024
               IDENT   resolved_at_def_site 42:2@13..33#ROOT2024
               IDENT   start_span 42:2@34..34#ROOT2024"#]],
@@ -135,21 +237,47 @@ fn test_fn_like_mk_literals() {
         r#""#,
         expect![[r#"
             SUBTREE $$ 1 1
+
+
+
+            SUBTREE $$ 1 1
               LITERAL ByteStr byte_string 1
               LITERAL Char c 1
               LITERAL Str string 1
+              LITERAL CStr cstring 1
               LITERAL Float 3.14f64 1
+              PUNCH   - [alone] 1
+              LITERAL Float 3.14f64 1
+              LITERAL Float 3.14 1
+              PUNCH   - [alone] 1
               LITERAL Float 3.14 1
               LITERAL Integer 123i64 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 123i64 1
+              LITERAL Integer 123 1
+              PUNCH   - [alone] 1
               LITERAL Integer 123 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               LITERAL ByteStr byte_string 42:2@0..100#ROOT2024
               LITERAL Char c 42:2@0..100#ROOT2024
               LITERAL Str string 42:2@0..100#ROOT2024
+              LITERAL CStr cstring 42:2@0..100#ROOT2024
+              LITERAL Float 3.14f64 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..100#ROOT2024
               LITERAL Float 3.14f64 42:2@0..100#ROOT2024
               LITERAL Float 3.14 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..100#ROOT2024
+              LITERAL Float 3.14 42:2@0..100#ROOT2024
+              LITERAL Integer 123i64 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..100#ROOT2024
               LITERAL Integer 123i64 42:2@0..100#ROOT2024
+              LITERAL Integer 123 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..100#ROOT2024
               LITERAL Integer 123 42:2@0..100#ROOT2024"#]],
     );
 }
@@ -161,10 +289,18 @@ fn test_fn_like_mk_idents() {
         r#""#,
         expect![[r#"
             SUBTREE $$ 1 1
+
+
+
+            SUBTREE $$ 1 1
               IDENT   standard 1
               IDENT   r#raw 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   standard 42:2@0..100#ROOT2024
               IDENT   r#raw 42:2@0..100#ROOT2024"#]],
     );
@@ -196,6 +332,30 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 1
               LITERAL Byte b 1
               PUNCH   , [alone] 1
+              LITERAL CStr null 1
+
+
+
+            SUBTREE $$ 1 1
+              LITERAL Integer 1u16 1
+              PUNCH   , [alone] 1
+              LITERAL Integer 2_u32 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 4i64 1
+              PUNCH   , [alone] 1
+              LITERAL Float 3.14f32 1
+              PUNCH   , [alone] 1
+              LITERAL Str hello bridge 1
+              PUNCH   , [alone] 1
+              LITERAL Str suffixedsuffix 1
+              PUNCH   , [alone] 1
+              LITERAL StrRaw(2) raw 1
+              PUNCH   , [alone] 1
+              LITERAL Char a 1
+              PUNCH   , [alone] 1
+              LITERAL Byte b 1
+              PUNCH   , [alone] 1
               LITERAL CStr null 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -218,11 +378,99 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 42:2@78..79#ROOT2024
               LITERAL Byte b 42:2@80..84#ROOT2024
               PUNCH   , [alone] 42:2@84..85#ROOT2024
+              LITERAL CStr null 42:2@86..93#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              LITERAL Integer 1u16 42:2@0..4#ROOT2024
+              PUNCH   , [alone] 42:2@4..5#ROOT2024
+              LITERAL Integer 2_u32 42:2@6..11#ROOT2024
+              PUNCH   , [alone] 42:2@11..12#ROOT2024
+              PUNCH   - [alone] 42:2@13..14#ROOT2024
+              LITERAL Integer 4i64 42:2@14..18#ROOT2024
+              PUNCH   , [alone] 42:2@18..19#ROOT2024
+              LITERAL Float 3.14f32 42:2@20..27#ROOT2024
+              PUNCH   , [alone] 42:2@27..28#ROOT2024
+              LITERAL Str hello bridge 42:2@29..43#ROOT2024
+              PUNCH   , [alone] 42:2@43..44#ROOT2024
+              LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024
+              PUNCH   , [alone] 42:2@61..62#ROOT2024
+              LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024
+              PUNCH   , [alone] 42:2@73..74#ROOT2024
+              LITERAL Char a 42:2@75..78#ROOT2024
+              PUNCH   , [alone] 42:2@78..79#ROOT2024
+              LITERAL Byte b 42:2@80..84#ROOT2024
+              PUNCH   , [alone] 42:2@84..85#ROOT2024
               LITERAL CStr null 42:2@86..93#ROOT2024"#]],
     );
 }
 
 #[test]
+fn test_fn_like_macro_negative_literals() {
+    assert_expand(
+        "fn_like_clone_tokens",
+        r###"-1u16, - 2_u32, -3.14f32, - 2.7"###,
+        expect![[r#"
+            SUBTREE $$ 1 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 1u16 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 2_u32 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Float 3.14f32 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Float 2.7 1
+
+
+
+            SUBTREE $$ 1 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 1u16 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Integer 2_u32 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Float 3.14f32 1
+              PUNCH   , [alone] 1
+              PUNCH   - [alone] 1
+              LITERAL Float 2.7 1"#]],
+        expect![[r#"
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..1#ROOT2024
+              LITERAL Integer 1u16 42:2@1..5#ROOT2024
+              PUNCH   , [alone] 42:2@5..6#ROOT2024
+              PUNCH   - [alone] 42:2@7..8#ROOT2024
+              LITERAL Integer 2_u32 42:2@9..14#ROOT2024
+              PUNCH   , [alone] 42:2@14..15#ROOT2024
+              PUNCH   - [alone] 42:2@16..17#ROOT2024
+              LITERAL Float 3.14f32 42:2@17..24#ROOT2024
+              PUNCH   , [alone] 42:2@24..25#ROOT2024
+              PUNCH   - [alone] 42:2@26..27#ROOT2024
+              LITERAL Float 2.7 42:2@28..31#ROOT2024
+
+
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              PUNCH   - [alone] 42:2@0..1#ROOT2024
+              LITERAL Integer 1u16 42:2@1..5#ROOT2024
+              PUNCH   , [alone] 42:2@5..6#ROOT2024
+              PUNCH   - [alone] 42:2@7..8#ROOT2024
+              LITERAL Integer 2_u32 42:2@9..14#ROOT2024
+              PUNCH   , [alone] 42:2@14..15#ROOT2024
+              PUNCH   - [alone] 42:2@16..17#ROOT2024
+              LITERAL Float 3.14f32 42:2@17..24#ROOT2024
+              PUNCH   , [alone] 42:2@24..25#ROOT2024
+              PUNCH   - [alone] 42:2@26..27#ROOT2024
+              LITERAL Float 2.7 42:2@28..31#ROOT2024"#]],
+    );
+}
+
+#[test]
 fn test_attr_macro() {
     // Corresponds to
     //    #[proc_macro_test::attr_error(some arguments)]
@@ -233,6 +481,15 @@ fn test_attr_macro() {
         r#"some arguments"#,
         expect![[r#"
             SUBTREE $$ 1 1
+              IDENT   mod 1
+              IDENT   m 1
+              SUBTREE {} 1 1
+
+            SUBTREE $$ 1 1
+              IDENT   some 1
+              IDENT   arguments 1
+
+            SUBTREE $$ 1 1
               IDENT   compile_error 1
               PUNCH   ! [alone] 1
               SUBTREE () 1 1
@@ -240,6 +497,15 @@ fn test_attr_macro() {
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   mod 42:2@0..3#ROOT2024
+              IDENT   m 42:2@4..5#ROOT2024
+              SUBTREE {} 42:2@6..7#ROOT2024 42:2@7..8#ROOT2024
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+              IDENT   some 42:2@0..4#ROOT2024
+              IDENT   arguments 42:2@5..14#ROOT2024
+
+            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   compile_error 42:2@0..100#ROOT2024
               PUNCH   ! [alone] 42:2@0..100#ROOT2024
               SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index a476a70a740..a0a45b269e4 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -32,9 +32,9 @@ pub fn assert_expand(
     macro_name: &str,
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
     expect: Expect,
-    expect_s: Expect,
+    expect_spanned: Expect,
 ) {
-    assert_expand_impl(macro_name, ra_fixture, None, expect, expect_s);
+    assert_expand_impl(macro_name, ra_fixture, None, expect, expect_spanned);
 }
 
 pub fn assert_expand_attr(
@@ -42,9 +42,9 @@ pub fn assert_expand_attr(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
     attr_args: &str,
     expect: Expect,
-    expect_s: Expect,
+    expect_spanned: Expect,
 ) {
-    assert_expand_impl(macro_name, ra_fixture, Some(attr_args), expect, expect_s);
+    assert_expand_impl(macro_name, ra_fixture, Some(attr_args), expect, expect_spanned);
 }
 
 fn assert_expand_impl(
@@ -52,7 +52,7 @@ fn assert_expand_impl(
     input: &str,
     attr: Option<&str>,
     expect: Expect,
-    expect_s: Expect,
+    expect_spanned: Expect,
 ) {
     let path = proc_macro_test_dylib_path();
     let expander = dylib::Expander::new(&path).unwrap();
@@ -60,20 +60,17 @@ fn assert_expand_impl(
     let def_site = TokenId(0);
     let call_site = TokenId(1);
     let mixed_site = TokenId(2);
-    let input_ts = parse_string(call_site, input);
+    let input_ts = parse_string(call_site, input).into_subtree(call_site);
     let attr_ts = attr.map(|attr| parse_string(call_site, attr).into_subtree(call_site));
+    let input_ts_string = format!("{input_ts:?}");
+    let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}"));
 
-    let res = expander
-        .expand(
-            macro_name,
-            input_ts.into_subtree(call_site),
-            attr_ts,
-            def_site,
-            call_site,
-            mixed_site,
-        )
-        .unwrap();
-    expect.assert_eq(&format!("{res:?}"));
+    let res =
+        expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap();
+    expect.assert_eq(&format!(
+        "{input_ts_string}\n\n{}\n\n{res:?}",
+        attr_ts_string.unwrap_or_default()
+    ));
 
     let def_site = Span {
         range: TextRange::new(0.into(), 150.into()),
@@ -93,15 +90,17 @@ fn assert_expand_impl(
     };
     let mixed_site = call_site;
 
-    let fixture = parse_string_spanned(call_site.anchor, call_site.ctx, input);
+    let fixture =
+        parse_string_spanned(call_site.anchor, call_site.ctx, input).into_subtree(call_site);
     let attr = attr.map(|attr| {
         parse_string_spanned(call_site.anchor, call_site.ctx, attr).into_subtree(call_site)
     });
+    let fixture_string = format!("{fixture:?}");
+    let attr_string = attr.as_ref().map(|it| format!("{it:?}"));
 
-    let res = expander
-        .expand(macro_name, fixture.into_subtree(call_site), attr, def_site, call_site, mixed_site)
-        .unwrap();
-    expect_s.assert_eq(&format!("{res:#?}"));
+    let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap();
+    expect_spanned
+        .assert_eq(&format!("{fixture_string}\n\n{}\n\n{res:#?}", attr_string.unwrap_or_default()));
 }
 
 pub(crate) fn list() -> Vec<String> {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index e7293b0b2ef..450def5461d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -18,6 +18,7 @@ pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) {
 
     let manifest_dir = package.manifest.parent();
     env.set("CARGO_MANIFEST_DIR", manifest_dir.as_str());
+    env.set("CARGO_MANIFEST_PATH", package.manifest.as_str());
 
     env.set("CARGO_PKG_VERSION", package.version.to_string());
     env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index c7c1b043186..d4055d9a0af 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -137,7 +137,12 @@ impl Sysroot {
                 }
 
                 let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs);
-                cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
+                if !envs.contains_key("RUSTUP_TOOLCHAIN")
+                    && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+                {
+                    cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
+                }
+
                 cmd
             }
             _ => toolchain::command(tool.path(), current_dir, envs),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 4ef9d816119..3722e2c7216 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -52,6 +52,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -136,6 +137,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -220,6 +222,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "an_example",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -304,6 +307,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "it",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -384,6 +388,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "libc",
                 "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "The Rust Project Developers",
                 "CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
                 "CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 4ef9d816119..3722e2c7216 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -52,6 +52,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -136,6 +137,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -220,6 +222,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "an_example",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -304,6 +307,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "it",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -384,6 +388,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "libc",
                 "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "The Rust Project Developers",
                 "CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
                 "CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 52089d1dbc2..7b156ea63a5 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -51,6 +51,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -134,6 +135,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "hello_world",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -217,6 +219,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "an_example",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -300,6 +303,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "it",
                 "CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+                "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "",
                 "CARGO_PKG_DESCRIPTION": "",
                 "CARGO_PKG_HOMEPAGE": "",
@@ -380,6 +384,7 @@
                 "CARGO": "$CARGO$",
                 "CARGO_CRATE_NAME": "libc",
                 "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+                "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
                 "CARGO_PKG_AUTHORS": "The Rust Project Developers",
                 "CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
                 "CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index a1e4adf0844..671e838421f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -4,6 +4,7 @@
 use std::{
     env, fmt,
     ops::AddAssign,
+    panic::{AssertUnwindSafe, catch_unwind},
     time::{SystemTime, UNIX_EPOCH},
 };
 
@@ -721,6 +722,7 @@ impl flags::AnalysisStats {
         let mut num_pats_unknown = 0;
         let mut num_pats_partially_unknown = 0;
         let mut num_pat_type_mismatches = 0;
+        let mut panics = 0;
         for &body_id in bodies {
             let name = body_id.name(db).unwrap_or_else(Name::missing);
             let module = body_id.module(db);
@@ -774,7 +776,20 @@ impl flags::AnalysisStats {
             }
             bar.set_message(msg);
             let body = db.body(body_id.into());
-            let inference_result = db.infer(body_id.into());
+            let inference_result = catch_unwind(AssertUnwindSafe(|| db.infer(body_id.into())));
+            let inference_result = match inference_result {
+                Ok(inference_result) => inference_result,
+                Err(p) => {
+                    if let Some(s) = p.downcast_ref::<&str>() {
+                        eprintln!("infer panicked for {}: {}", full_name(), s);
+                    } else if let Some(s) = p.downcast_ref::<String>() {
+                        eprintln!("infer panicked for {}: {}", full_name(), s);
+                    }
+                    panics += 1;
+                    bar.inc(1);
+                    continue;
+                }
+            };
             // This query is LRU'd, so actually calling it will skew the timing results.
             let sm = || db.body_with_source_map(body_id.into()).1;
 
@@ -1008,6 +1023,7 @@ impl flags::AnalysisStats {
             percentage(num_pats_partially_unknown, num_pats),
             num_pat_type_mismatches
         );
+        eprintln!("  panics: {}", panics);
         eprintln!("{:<20} {}", "Inference:", inference_time);
         report_metric("unknown type", num_exprs_unknown, "#");
         report_metric("type mismatches", num_expr_type_mismatches, "#");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
index 57f95d114d9..16f351272b6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
@@ -150,8 +150,8 @@ xflags::xflags! {
             optional --disable-proc-macros
             /// Run the proc-macro-srv binary at the specified path.
             optional --proc-macro-srv path: PathBuf
-            /// Run cache priming in parallel.
-            optional --parallel
+            /// The number of threads to use. Defaults to the number of physical cores.
+            optional --num-threads num_threads: usize
         }
 
         cmd ssr {
@@ -299,7 +299,7 @@ pub struct PrimeCaches {
     pub disable_build_scripts: bool,
     pub disable_proc_macros: bool,
     pub proc_macro_srv: Option<PathBuf>,
-    pub parallel: bool,
+    pub num_threads: Option<usize>,
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
index 46fb701ab42..467d8a53884 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
@@ -52,7 +52,7 @@ impl flags::PrimeCaches {
             elapsed.memory.allocated.megabytes() as u64
         );
 
-        let threads = if self.parallel { num_cpus::get() } else { 1 };
+        let threads = self.num_threads.unwrap_or_else(num_cpus::get_physical);
         ide_db::prime_caches::parallel_prime_caches(&db, threads, &|_| ());
 
         let elapsed = stop_watch.elapsed();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index fc312439d58..0e418240db0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -470,7 +470,11 @@ impl FlycheckActor {
                 let mut cmd =
                     toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env);
                 if let Some(sysroot_root) = &self.sysroot_root {
-                    cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
+                    if !options.extra_env.contains_key("RUSTUP_TOOLCHAIN")
+                        && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+                    {
+                        cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
+                    }
                 }
                 cmd.arg(command);
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 3b3b9c87975..a870232d4a0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -3,7 +3,11 @@
 //!
 //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 
-use std::{ops::Not as _, time::Instant};
+use std::{
+    ops::Not as _,
+    panic::AssertUnwindSafe,
+    time::{Duration, Instant},
+};
 
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
@@ -19,6 +23,7 @@ use parking_lot::{
 use proc_macro_api::ProcMacroClient;
 use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::thread;
 use tracing::{Level, span, trace};
 use triomphe::Arc;
 use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath};
@@ -40,6 +45,7 @@ use crate::{
     test_runner::{CargoTestHandle, CargoTestMessage},
 };
 
+#[derive(Debug)]
 pub(crate) struct FetchWorkspaceRequest {
     pub(crate) path: Option<AbsPathBuf>,
     pub(crate) force_crate_graph_reload: bool,
@@ -78,6 +84,7 @@ pub(crate) struct GlobalState {
 
     pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
     pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
+    pub(crate) cancellation_pool: thread::Pool,
 
     pub(crate) config: Arc<Config>,
     pub(crate) config_errors: Option<ConfigErrors>,
@@ -114,6 +121,11 @@ pub(crate) struct GlobalState {
     pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
     pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,
 
+    // Debouncing channel for fetching the workspace
+    // we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
+    // of a VCS operation like `git switch`)
+    pub(crate) fetch_ws_receiver: Option<(Receiver<Instant>, FetchWorkspaceRequest)>,
+
     // VFS
     pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
     pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
@@ -210,6 +222,7 @@ impl GlobalState {
             let handle = TaskPool::new_with_threads(sender, 1);
             Handle { handle, receiver }
         };
+        let cancellation_pool = thread::Pool::new(1);
 
         let task_queue = {
             let (sender, receiver) = unbounded();
@@ -230,6 +243,7 @@ impl GlobalState {
             req_queue: ReqQueue::default(),
             task_pool,
             fmt_pool,
+            cancellation_pool,
             loader,
             config: Arc::new(config.clone()),
             analysis_host,
@@ -264,6 +278,8 @@ impl GlobalState {
             discover_sender,
             discover_receiver,
 
+            fetch_ws_receiver: None,
+
             vfs: Arc::new(RwLock::new((vfs::Vfs::default(), Default::default()))),
             vfs_config_version: 0,
             vfs_progress_config_version: 0,
@@ -290,7 +306,6 @@ impl GlobalState {
 
     pub(crate) fn process_changes(&mut self) -> bool {
         let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
-
         // We cannot directly resolve a change in a ratoml file to a format
         // that can be used by the config module because config talks
         // in `SourceRootId`s instead of `FileId`s and `FileId` -> `SourceRootId`
@@ -298,66 +313,75 @@ impl GlobalState {
         let mut modified_ratoml_files: FxHashMap<FileId, (ChangeKind, vfs::VfsPath)> =
             FxHashMap::default();
 
-        let (change, modified_rust_files, workspace_structure_change) = {
-            let mut change = ChangeWithProcMacros::default();
-            let mut guard = self.vfs.write();
-            let changed_files = guard.0.take_changes();
-            if changed_files.is_empty() {
-                return false;
-            }
+        let mut change = ChangeWithProcMacros::default();
+        let mut guard = self.vfs.write();
+        let changed_files = guard.0.take_changes();
+        if changed_files.is_empty() {
+            return false;
+        }
 
-            // downgrade to read lock to allow more readers while we are normalizing text
-            let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
-            let vfs: &Vfs = &guard.0;
-
-            let mut workspace_structure_change = None;
-            // A file was added or deleted
-            let mut has_structure_changes = false;
-            let mut bytes = vec![];
-            let mut modified_rust_files = vec![];
-            for file in changed_files.into_values() {
-                let vfs_path = vfs.file_path(file.file_id);
-                if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
-                    // Remember ids to use them after `apply_changes`
-                    modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
-                }
+        let (change, modified_rust_files, workspace_structure_change) =
+            self.cancellation_pool.scoped(|s| {
+                // start cancellation in parallel, this will kick off lru eviction
+                // allowing us to do meaningful work while waiting
+                let analysis_host = AssertUnwindSafe(&mut self.analysis_host);
+                s.spawn(thread::ThreadIntent::LatencySensitive, || {
+                    { analysis_host }.0.request_cancellation()
+                });
+
+                // downgrade to read lock to allow more readers while we are normalizing text
+                let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
+                let vfs: &Vfs = &guard.0;
+
+                let mut workspace_structure_change = None;
+                // A file was added or deleted
+                let mut has_structure_changes = false;
+                let mut bytes = vec![];
+                let mut modified_rust_files = vec![];
+                for file in changed_files.into_values() {
+                    let vfs_path = vfs.file_path(file.file_id);
+                    if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
+                        // Remember ids to use them after `apply_changes`
+                        modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
+                    }
 
-                if let Some(path) = vfs_path.as_path() {
-                    has_structure_changes |= file.is_created_or_deleted();
+                    if let Some(path) = vfs_path.as_path() {
+                        has_structure_changes |= file.is_created_or_deleted();
 
-                    if file.is_modified() && path.extension() == Some("rs") {
-                        modified_rust_files.push(file.file_id);
-                    }
+                        if file.is_modified() && path.extension() == Some("rs") {
+                            modified_rust_files.push(file.file_id);
+                        }
 
-                    let additional_files = self
-                        .config
-                        .discover_workspace_config()
-                        .map(|cfg| {
-                            cfg.files_to_watch.iter().map(String::as_str).collect::<Vec<&str>>()
-                        })
-                        .unwrap_or_default();
-
-                    let path = path.to_path_buf();
-                    if file.is_created_or_deleted() {
-                        workspace_structure_change.get_or_insert((path, false)).1 |=
-                            self.crate_graph_file_dependencies.contains(vfs_path);
-                    } else if reload::should_refresh_for_change(
-                        &path,
-                        file.kind(),
-                        &additional_files,
-                    ) {
-                        trace!(?path, kind = ?file.kind(), "refreshing for a change");
-                        workspace_structure_change.get_or_insert((path.clone(), false));
+                        let additional_files = self
+                            .config
+                            .discover_workspace_config()
+                            .map(|cfg| {
+                                cfg.files_to_watch.iter().map(String::as_str).collect::<Vec<&str>>()
+                            })
+                            .unwrap_or_default();
+
+                        let path = path.to_path_buf();
+                        if file.is_created_or_deleted() {
+                            workspace_structure_change.get_or_insert((path, false)).1 |=
+                                self.crate_graph_file_dependencies.contains(vfs_path);
+                        } else if reload::should_refresh_for_change(
+                            &path,
+                            file.kind(),
+                            &additional_files,
+                        ) {
+                            trace!(?path, kind = ?file.kind(), "refreshing for a change");
+                            workspace_structure_change.get_or_insert((path.clone(), false));
+                        }
                     }
-                }
 
-                // Clear native diagnostics when their file gets deleted
-                if !file.exists() {
-                    self.diagnostics.clear_native_for(file.file_id);
-                }
+                    // Clear native diagnostics when their file gets deleted
+                    if !file.exists() {
+                        self.diagnostics.clear_native_for(file.file_id);
+                    }
 
-                let text =
-                    if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
+                    let text = if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) =
+                        file.change
+                    {
                         String::from_utf8(v).ok().map(|text| {
                             // FIXME: Consider doing normalization in the `vfs` instead? That allows
                             // getting rid of some locking
@@ -367,29 +391,28 @@ impl GlobalState {
                     } else {
                         None
                     };
-                // delay `line_endings_map` changes until we are done normalizing the text
-                // this allows delaying the re-acquisition of the write lock
-                bytes.push((file.file_id, text));
-            }
-            let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
-            bytes.into_iter().for_each(|(file_id, text)| {
-                let text = match text {
-                    None => None,
-                    Some((text, line_endings)) => {
-                        line_endings_map.insert(file_id, line_endings);
-                        Some(text)
-                    }
-                };
-                change.change_file(file_id, text);
+                    // delay `line_endings_map` changes until we are done normalizing the text
+                    // this allows delaying the re-acquisition of the write lock
+                    bytes.push((file.file_id, text));
+                }
+                let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
+                bytes.into_iter().for_each(|(file_id, text)| {
+                    let text = match text {
+                        None => None,
+                        Some((text, line_endings)) => {
+                            line_endings_map.insert(file_id, line_endings);
+                            Some(text)
+                        }
+                    };
+                    change.change_file(file_id, text);
+                });
+                if has_structure_changes {
+                    let roots = self.source_root_config.partition(vfs);
+                    change.set_roots(roots);
+                }
+                (change, modified_rust_files, workspace_structure_change)
             });
-            if has_structure_changes {
-                let roots = self.source_root_config.partition(vfs);
-                change.set_roots(roots);
-            }
-            (change, modified_rust_files, workspace_structure_change)
-        };
 
-        let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
         self.analysis_host.apply_change(change);
         if !modified_ratoml_files.is_empty()
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
@@ -508,11 +531,7 @@ impl GlobalState {
             if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
                 let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change")
                     .entered();
-
-                self.fetch_workspaces_queue.request_op(
-                    format!("workspace vfs file change: {path}"),
-                    FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
-                );
+                self.enqueue_workspace_fetch(path, force_crate_graph_reload);
             }
         }
 
@@ -660,6 +679,30 @@ impl GlobalState {
             None
         })
     }
+
+    fn enqueue_workspace_fetch(&mut self, path: AbsPathBuf, force_crate_graph_reload: bool) {
+        let already_requested = self.fetch_workspaces_queue.op_requested()
+            && !self.fetch_workspaces_queue.op_in_progress();
+        if self.fetch_ws_receiver.is_none() && already_requested {
+            // Don't queue up a new fetch request if we already have done so
+            // Otherwise we will re-fetch in quick succession which is unnecessary
+            // Note though, that if one is already in progress, we *want* to re-queue
+            // as the in-progress fetch might not have the latest changes in it anymore
+            // FIXME: We should cancel the in-progress fetch here
+            return;
+        }
+
+        self.fetch_ws_receiver = Some((
+            crossbeam_channel::after(Duration::from_millis(100)),
+            FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
+        ));
+    }
+
+    pub(crate) fn debounce_workspace_fetch(&mut self) {
+        if let Some((fetch_receiver, _)) = &mut self.fetch_ws_receiver {
+            *fetch_receiver = crossbeam_channel::after(Duration::from_millis(100));
+        }
+    }
 }
 
 impl Drop for GlobalState {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index bd213ffa57a..0c0438c4b8f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -8,7 +8,7 @@ use std::{
     time::{Duration, Instant},
 };
 
-use crossbeam_channel::{Receiver, select};
+use crossbeam_channel::{Receiver, never, select};
 use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _};
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
@@ -71,6 +71,7 @@ enum Event {
     Flycheck(FlycheckMessage),
     TestResult(CargoTestMessage),
     DiscoverProject(DiscoverProjectMessage),
+    FetchWorkspaces(FetchWorkspaceRequest),
 }
 
 impl fmt::Display for Event {
@@ -83,6 +84,7 @@ impl fmt::Display for Event {
             Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
             Event::TestResult(_) => write!(f, "Event::TestResult"),
             Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
+            Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"),
         }
     }
 }
@@ -150,6 +152,7 @@ impl fmt::Debug for Event {
             }
             _ => (),
         }
+
         match self {
             Event::Lsp(it) => fmt::Debug::fmt(it, f),
             Event::Task(it) => fmt::Debug::fmt(it, f),
@@ -158,6 +161,7 @@ impl fmt::Debug for Event {
             Event::Flycheck(it) => fmt::Debug::fmt(it, f),
             Event::TestResult(it) => fmt::Debug::fmt(it, f),
             Event::DiscoverProject(it) => fmt::Debug::fmt(it, f),
+            Event::FetchWorkspaces(it) => fmt::Debug::fmt(it, f),
         }
     }
 }
@@ -251,7 +255,7 @@ impl GlobalState {
     }
 
     fn next_event(
-        &self,
+        &mut self,
         inbox: &Receiver<lsp_server::Message>,
     ) -> Result<Option<Event>, crossbeam_channel::RecvError> {
         // Make sure we reply to formatting requests ASAP so the editor doesn't block
@@ -283,6 +287,10 @@ impl GlobalState {
 
             recv(self.discover_receiver) -> task =>
                 task.map(Event::DiscoverProject),
+
+            recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => {
+                Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1))
+            },
         }
         .map(Some)
     }
@@ -412,6 +420,9 @@ impl GlobalState {
                     self.handle_discover_msg(message);
                 }
             }
+            Event::FetchWorkspaces(req) => {
+                self.fetch_workspaces_queue.request_op("project structure change".to_owned(), req)
+            }
         }
         let event_handling_duration = loop_start.elapsed();
         let (state_changed, memdocs_added_or_removed) = if self.vfs_done {
@@ -830,6 +841,7 @@ impl GlobalState {
         match message {
             vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
                 let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
+                self.debounce_workspace_fetch();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
                     let path = VfsPath::from(path);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
index 709d99bda75..7af5b48bb7a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
@@ -36,7 +36,7 @@ impl<Args, Output> Default for OpQueue<Args, Output> {
     }
 }
 
-impl<Args, Output> OpQueue<Args, Output> {
+impl<Args: std::fmt::Debug, Output> OpQueue<Args, Output> {
     /// Request an operation to start.
     pub(crate) fn request_op(&mut self, reason: Cause, args: Args) {
         self.op_requested = Some((reason, args));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 55ed1923653..ae9e3e99874 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -69,6 +69,7 @@ impl GlobalState {
     /// are ready to do semantic work.
     pub(crate) fn is_quiescent(&self) -> bool {
         self.vfs_done
+            && self.fetch_ws_receiver.is_none()
             && !self.fetch_workspaces_queue.op_in_progress()
             && !self.fetch_build_data_queue.op_in_progress()
             && !self.fetch_proc_macros_queue.op_in_progress()
@@ -659,6 +660,10 @@ impl GlobalState {
                         .chain(
                             ws.sysroot
                                 .root()
+                                .filter(|_| {
+                                    !self.config.extra_env(None).contains_key("RUSTUP_TOOLCHAIN")
+                                        && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+                                })
                                 .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), Some(it.to_string()))),
                         )
                         .collect(),
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 7bda106764b..b37aded6f68 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -17,6 +17,7 @@ jod-thread = "1.0.0"
 crossbeam-channel.workspace = true
 itertools.workspace = true
 tracing.workspace = true
+crossbeam-utils = "0.8.21"
 # Think twice before adding anything here
 
 [target.'cfg(unix)'.dependencies]
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
index a8de4db624f..8d76c5fd1fb 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
@@ -8,6 +8,7 @@
 //! the threading utilities in [`crate::thread`].
 
 use std::{
+    marker::PhantomData,
     panic::{self, UnwindSafe},
     sync::{
         Arc,
@@ -16,8 +17,9 @@ use std::{
 };
 
 use crossbeam_channel::{Receiver, Sender};
+use crossbeam_utils::sync::WaitGroup;
 
-use super::{Builder, JoinHandle, ThreadIntent};
+use crate::thread::{Builder, JoinHandle, ThreadIntent};
 
 pub struct Pool {
     // `_handles` is never read: the field is present
@@ -79,9 +81,6 @@ impl Pool {
         Self { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
     }
 
-    /// # Panics
-    ///
-    /// Panics if job panics
     pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
     where
         F: FnOnce() + Send + UnwindSafe + 'static,
@@ -97,6 +96,17 @@ impl Pool {
         self.job_sender.send(job).unwrap();
     }
 
+    pub fn scoped<'pool, 'scope, F, R>(&'pool self, f: F) -> R
+    where
+        F: FnOnce(&Scope<'pool, 'scope>) -> R,
+    {
+        let wg = WaitGroup::new();
+        let scope = Scope { pool: self, wg, _marker: PhantomData };
+        let r = f(&scope);
+        scope.wg.wait();
+        r
+    }
+
     #[must_use]
     pub fn len(&self) -> usize {
         self.extant_tasks.load(Ordering::SeqCst)
@@ -107,3 +117,36 @@ impl Pool {
         self.len() == 0
     }
 }
+
+pub struct Scope<'pool, 'scope> {
+    pool: &'pool Pool,
+    wg: WaitGroup,
+    _marker: PhantomData<fn(&'scope ()) -> &'scope ()>,
+}
+
+impl<'scope> Scope<'_, 'scope> {
+    pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
+    where
+        F: 'scope + FnOnce() + Send + UnwindSafe,
+    {
+        let wg = self.wg.clone();
+        let f = Box::new(move || {
+            if cfg!(debug_assertions) {
+                intent.assert_is_used_on_current_thread();
+            }
+            f();
+            drop(wg);
+        });
+
+        let job = Job {
+            requested_intent: intent,
+            f: unsafe {
+                std::mem::transmute::<
+                    Box<dyn 'scope + FnOnce() + Send + UnwindSafe>,
+                    Box<dyn 'static + FnOnce() + Send + UnwindSafe>,
+                >(f)
+            },
+        };
+        self.pool.job_sender.send(job).unwrap();
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index da0bfd4f37f..e60243f2c91 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -109,6 +109,67 @@ impl GenericParamsOwnerEdit for ast::Trait {
     }
 }
 
+impl GenericParamsOwnerEdit for ast::TraitAlias {
+    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
+        match self.generic_param_list() {
+            Some(it) => it,
+            None => {
+                let position = if let Some(name) = self.name() {
+                    Position::after(name.syntax)
+                } else if let Some(trait_token) = self.trait_token() {
+                    Position::after(trait_token)
+                } else {
+                    Position::last_child_of(self.syntax())
+                };
+                create_generic_param_list(position)
+            }
+        }
+    }
+
+    fn get_or_create_where_clause(&self) -> ast::WhereClause {
+        if self.where_clause().is_none() {
+            let position = match self.semicolon_token() {
+                Some(tok) => Position::before(tok),
+                None => Position::last_child_of(self.syntax()),
+            };
+            create_where_clause(position);
+        }
+        self.where_clause().unwrap()
+    }
+}
+
+impl GenericParamsOwnerEdit for ast::TypeAlias {
+    fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
+        match self.generic_param_list() {
+            Some(it) => it,
+            None => {
+                let position = if let Some(name) = self.name() {
+                    Position::after(name.syntax)
+                } else if let Some(trait_token) = self.type_token() {
+                    Position::after(trait_token)
+                } else {
+                    Position::last_child_of(self.syntax())
+                };
+                create_generic_param_list(position)
+            }
+        }
+    }
+
+    fn get_or_create_where_clause(&self) -> ast::WhereClause {
+        if self.where_clause().is_none() {
+            let position = match self.eq_token() {
+                Some(tok) => Position::before(tok),
+                None => match self.semicolon_token() {
+                    Some(tok) => Position::before(tok),
+                    None => Position::last_child_of(self.syntax()),
+                },
+            };
+            create_where_clause(position);
+        }
+        self.where_clause().unwrap()
+    }
+}
+
 impl GenericParamsOwnerEdit for ast::Struct {
     fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
         match self.generic_param_list() {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 596f73e0b10..fab4cb287c3 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -13,6 +13,7 @@
 
 mod quote;
 
+use either::Either;
 use itertools::Itertools;
 use parser::{Edition, T};
 use rowan::NodeOrToken;
@@ -881,7 +882,7 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat
 }
 
 pub fn where_pred(
-    path: ast::Type,
+    path: Either<ast::Lifetime, ast::Type>,
     bounds: impl IntoIterator<Item = ast::TypeBound>,
 ) -> ast::WherePred {
     let bounds = bounds.into_iter().join(" + ");
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index f6ca5ab6c8c..96e1301f227 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -662,10 +662,6 @@ impl ProcMacroExpander for IdentityProcMacroExpander {
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         Ok(subtree.clone())
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Expands to a macro_rules! macro, for issue #18089.
@@ -697,10 +693,6 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander {
             #subtree
         })
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Pastes the attribute input as its output
@@ -721,10 +713,6 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
             .cloned()
             .ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into()))
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 #[derive(Debug)]
@@ -756,10 +744,6 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander {
         top_subtree_delimiter_mut.close = def_site;
         Ok(result)
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 #[derive(Debug)]
@@ -791,10 +775,6 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
         traverse(&mut builder, input.iter());
         Ok(builder.build())
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Replaces every literal with an empty string literal and every identifier with its first letter,
@@ -835,10 +815,6 @@ impl ProcMacroExpander for ShortenProcMacroExpander {
             }
         }
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -864,10 +840,6 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander {
             #symbol()
         })
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -919,10 +891,6 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander {
             }
         })
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -950,8 +918,4 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander {
         }
         Ok(subtree.clone())
     }
-
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.as_any().type_id() == std::any::TypeId::of::<Self>()
-    }
 }
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 1dbc07c0929..14574a6456b 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -817,6 +817,58 @@ impl<S> fmt::Display for Ident<S> {
     }
 }
 
+impl<S> Literal<S> {
+    pub fn display_no_minus(&self) -> impl fmt::Display {
+        struct NoMinus<'a, S>(&'a Literal<S>);
+        impl<S> fmt::Display for NoMinus<'_, S> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                let symbol =
+                    self.0.symbol.as_str().strip_prefix('-').unwrap_or(self.0.symbol.as_str());
+                match self.0.kind {
+                    LitKind::Byte => write!(f, "b'{symbol}'"),
+                    LitKind::Char => write!(f, "'{symbol}'"),
+                    LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{symbol}"),
+                    LitKind::Str => write!(f, "\"{symbol}\""),
+                    LitKind::ByteStr => write!(f, "b\"{symbol}\""),
+                    LitKind::CStr => write!(f, "c\"{symbol}\""),
+                    LitKind::StrRaw(num_of_hashes) => {
+                        let num_of_hashes = num_of_hashes as usize;
+                        write!(
+                            f,
+                            r#"r{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+                            "",
+                            text = symbol
+                        )
+                    }
+                    LitKind::ByteStrRaw(num_of_hashes) => {
+                        let num_of_hashes = num_of_hashes as usize;
+                        write!(
+                            f,
+                            r#"br{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+                            "",
+                            text = symbol
+                        )
+                    }
+                    LitKind::CStrRaw(num_of_hashes) => {
+                        let num_of_hashes = num_of_hashes as usize;
+                        write!(
+                            f,
+                            r#"cr{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+                            "",
+                            text = symbol
+                        )
+                    }
+                }?;
+                if let Some(suffix) = &self.0.suffix {
+                    write!(f, "{suffix}")?;
+                }
+                Ok(())
+            }
+        }
+        NoMinus(self)
+    }
+}
+
 impl<S> fmt::Display for Literal<S> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.kind {
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 11a37c218f7..18fb097aad7 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -5730,9 +5730,9 @@
             "license": "MIT"
         },
         "node_modules/undici": {
-            "version": "6.21.1",
-            "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
-            "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
+            "version": "6.21.3",
+            "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
+            "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
             "dev": true,
             "license": "MIT",
             "engines": {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 90e4d65bf96..5b47d1bbaed 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-6e23095adf9209614a45f7f75fea36dad7b92afb
+a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 6195de5d202..bb7d83c4b7d 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -14,7 +14,7 @@ write-json = "0.1.4"
 xshell.workspace = true
 xflags = "0.3.2"
 time = { version = "0.3", default-features = false }
-zip = { version = "2.4", default-features = false, features = ["deflate-flate2", "flate2", "time"] }
+zip = { version = "3.0", default-features = false, features = ["deflate-flate2", "time"] }
 stdx.workspace = true
 proc-macro2 = "1.0.94"
 quote = "1.0.40"
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 0b389377011..5c862e95400 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -344,17 +344,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "dbus"
-version = "0.9.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
-dependencies = [
- "libc",
- "libdbus-sys",
- "winapi",
-]
-
-[[package]]
 name = "derive_builder"
 version = "0.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -824,16 +813,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
-name = "libdbus-sys"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
-dependencies = [
- "cc",
- "pkg-config",
-]
-
-[[package]]
 name = "linereader"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -906,9 +885,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.49"
+version = "0.4.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4"
+checksum = "f72bc08f096e1fb15cfc382babe218317c2897d2040f967c4db40d156ca28e21"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -921,7 +900,6 @@ dependencies = [
  "hex",
  "log",
  "memchr",
- "once_cell",
  "opener",
  "pulldown-cmark 0.10.3",
  "regex",
@@ -1070,12 +1048,11 @@ dependencies = [
 
 [[package]]
 name = "opener"
-version = "0.7.2"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681"
+checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c"
 dependencies = [
  "bstr",
- "dbus",
  "normpath",
  "windows-sys",
 ]
@@ -1906,22 +1883,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
 name = "winapi-util"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1931,12 +1892,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
 name = "windows-core"
 version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 10fde31306d..ee2ada5aa2b 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.49"
+version = "0.4.50"
 default-features = false
 features = ["search"]
diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs
index ad2770d43e3..b7abeb02298 100644
--- a/tests/assembly/asm/aarch64-types.rs
+++ b/tests/assembly/asm/aarch64-types.rs
@@ -86,12 +86,11 @@ pub unsafe fn sym_static() {
 
 // Regression test for #75761
 // CHECK-LABEL: {{("#)?}}issue_75761{{"?}}
-// aarch64: str {{.*}}x30
-// arm64ec: stp {{.*}}x30
+// x29 holds the frame pointer, right next to x30, so ldp/stp happens sometimes
+// CHECK: st[[MAY_PAIR:(r|p).*]]x30
 // CHECK: //APP
 // CHECK: //NO_APP
-// aarch64: ldr {{.*}}x30
-// arm64ec: ldp {{.*}}x30
+// CHECK: ld[[MAY_PAIR]]x30
 #[no_mangle]
 pub unsafe fn issue_75761() {
     asm!("", out("v0") _, out("x30") _);
diff --git a/tests/codegen/autodiff/generic.rs b/tests/codegen/autodiff/generic.rs
new file mode 100644
index 00000000000..15e7d8a4957
--- /dev/null
+++ b/tests/codegen/autodiff/generic.rs
@@ -0,0 +1,42 @@
+//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[autodiff(d_square, Reverse, Duplicated, Active)]
+fn square<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
+    *x * *x
+}
+
+// Ensure that `d_square::<f64>` code is generated even if `square::<f64>` was never called
+//
+// CHECK: ; generic::square
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal {{.*}} double
+// CHECK-NEXT: start:
+// CHECK-NOT: ret
+// CHECK: fmul double
+
+// Ensure that `d_square::<f32>` code is generated
+//
+// CHECK: ; generic::square
+// CHECK-NEXT: ; Function Attrs: {{.*}}
+// CHECK-NEXT: define internal {{.*}} float
+// CHECK-NEXT: start:
+// CHECK-NOT: ret
+// CHECK: fmul float
+
+fn main() {
+    let xf32: f32 = std::hint::black_box(3.0);
+    let xf64: f64 = std::hint::black_box(3.0);
+
+    let outputf32 = square::<f32>(&xf32);
+    assert_eq!(9.0, outputf32);
+
+    let mut df_dxf64: f64 = std::hint::black_box(0.0);
+
+    let output_f64 = d_square::<f64>(&xf64, &mut df_dxf64, 1.0);
+    assert_eq!(6.0, df_dxf64);
+}
diff --git a/tests/codegen/frame-pointer.rs b/tests/codegen/frame-pointer.rs
index 1f7c9a59c98..23989653fa8 100644
--- a/tests/codegen/frame-pointer.rs
+++ b/tests/codegen/frame-pointer.rs
@@ -26,8 +26,10 @@ pub fn peach(x: u32) -> u32 {
 
 // CHECK: attributes [[PEACH_ATTRS]] = {
 // x64-linux-NOT: {{.*}}"frame-pointer"{{.*}}
-// aarch64-linux-NOT: {{.*}}"frame-pointer"{{.*}}
 // x64-apple-SAME: {{.*}}"frame-pointer"="all"
 // force-SAME: {{.*}}"frame-pointer"="all"
+//
+// AAPCS64 demands frame pointers:
+// aarch64-linux-SAME: {{.*}}"frame-pointer"="non-leaf"
 // aarch64-apple-SAME: {{.*}}"frame-pointer"="non-leaf"
 // CHECK-SAME: }
diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map
index 9f8dc8d6cbb..53128dd7a48 100644
--- a/tests/coverage/async_closure.cov-map
+++ b/tests/coverage/async_closure.cov-map
@@ -37,32 +37,29 @@ Number of file 0 mappings: 8
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
 Function name: async_closure::main::{closure#0}::{closure#0}::<i16>
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24]
 Number of files: 1
 - file 0 => $DIR/async_closure.rs
 Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35)
-- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36)
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36)
 Highest counter ID seen: c0
 
diff --git a/tests/coverage/unused-local-file.coverage b/tests/coverage/unused-local-file.coverage
new file mode 100644
index 00000000000..8f5a32f6d70
--- /dev/null
+++ b/tests/coverage/unused-local-file.coverage
@@ -0,0 +1,7 @@
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Force this function to be generated in its home crate, so that it ends up
+   LL|       |// with normal coverage metadata.
+   LL|       |#[inline(never)]
+   LL|      1|pub fn external_function() {}
+
diff --git a/tests/coverage/unused-local-file.rs b/tests/coverage/unused-local-file.rs
new file mode 100644
index 00000000000..cf43c62d703
--- /dev/null
+++ b/tests/coverage/unused-local-file.rs
@@ -0,0 +1,22 @@
+//! If we give LLVM a local file table for a function, but some of the entries
+//! in that table have no associated mapping regions, then an assertion failure
+//! will occur in LLVM. We therefore need to detect and skip any function that
+//! would trigger that assertion.
+//!
+//! To test that this case is handled, even before adding code that could allow
+//! it to happen organically (for expansion region support), we use a special
+//! testing-only flag to force it to occur.
+
+//@ edition: 2024
+//@ compile-flags: -Zcoverage-options=inject-unused-local-file
+
+// The `llvm-cov` tool will complain if the test binary ends up having no
+// coverage metadata at all. To prevent that, we also link to instrumented
+// code in an auxiliary crate that doesn't have the special flag set.
+
+//@ aux-build: discard_all_helper.rs
+extern crate discard_all_helper;
+
+fn main() {
+    discard_all_helper::external_function();
+}
diff --git a/tests/crashes/113379.rs b/tests/crashes/113379.rs
deleted file mode 100644
index 7163cbc3934..00000000000
--- a/tests/crashes/113379.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ known-bug: #113379
-
-async fn f999() -> Vec<usize> {
-    'b: {
-        continue 'b;
-    }
-}
diff --git a/tests/crashes/121623.rs b/tests/crashes/121623.rs
deleted file mode 100644
index 3c01a7f452c..00000000000
--- a/tests/crashes/121623.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #121623
-fn main() {
-    match () {
-        _ => 'b: {
-            continue 'b;
-        }
-    }
-}
diff --git a/tests/crashes/122704.rs b/tests/crashes/122704.rs
deleted file mode 100644
index d6c07be8318..00000000000
--- a/tests/crashes/122704.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ known-bug: #122704
-use std::any::Any;
-
-pub struct Foo {
-    bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>,
-}
-
-impl Foo {
-    pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
-        self.bar = Box::new(|baz| Box::new(f(baz)));
-    }
-}
-
-fn main() {}
diff --git a/tests/crashes/133199.rs b/tests/crashes/133199.rs
deleted file mode 100644
index 76535fa83a6..00000000000
--- a/tests/crashes/133199.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #133199
-//@ aux-build: aux133199.rs
-
-extern crate aux133199;
-
-use aux133199::FixedBitSet;
-
-fn main() {
-    FixedBitSet::<7>::new();
-    //~^ ERROR
-}
diff --git a/tests/crashes/136894.rs b/tests/crashes/136894.rs
deleted file mode 100644
index 26bbb78717e..00000000000
--- a/tests/crashes/136894.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #136894
-#![feature(generic_const_exprs)]
-#![crate_type = "lib"]
-#![allow(incomplete_features, dead_code)]
-
-struct X<T>([(); f::<T>()]) where [(); f::<T>()]:;
-
-const fn f<T>() -> usize { panic!() }
diff --git a/tests/crashes/137813.rs b/tests/crashes/137813.rs
deleted file mode 100644
index 5d205ee5331..00000000000
--- a/tests/crashes/137813.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ known-bug: #137813
-trait AssocConst {
-    const A: u8;
-}
-
-impl<T> AssocConst for (T,) {
-    const A: u8 = 0;
-}
-
-trait Trait {}
-
-impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
-
-fn foo()
-where
-    (): Trait,
-{
-}
diff --git a/tests/crashes/139905.rs b/tests/crashes/139905.rs
new file mode 100644
index 00000000000..7da622aaaba
--- /dev/null
+++ b/tests/crashes/139905.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #139905
+trait a<const b: bool> {}
+impl a<{}> for () {}
+trait c {}
+impl<const d: u8> c for () where (): a<d> {}
+impl c for () {}
diff --git a/tests/crashes/140011.rs b/tests/crashes/140011.rs
new file mode 100644
index 00000000000..b9d57a2822d
--- /dev/null
+++ b/tests/crashes/140011.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #140011
+//@compile-flags: -Wrust-2021-incompatible-closure-captures
+enum b {
+    c(d),
+    e(f),
+}
+struct f;
+fn g() {
+    let h;
+    || b::e(a) = h;
+}
diff --git a/tests/crashes/140099.rs b/tests/crashes/140099.rs
new file mode 100644
index 00000000000..fca12910055
--- /dev/null
+++ b/tests/crashes/140099.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #140099
+struct a;
+impl From for a where for<'any> &'any mut (): Clone {}
+fn b() -> Result<(), std::convert::Infallible> {
+    || -> Result<_, a> { b()? }
+}
diff --git a/tests/crashes/140100.rs b/tests/crashes/140100.rs
new file mode 100644
index 00000000000..0836ffe2d92
--- /dev/null
+++ b/tests/crashes/140100.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #140100
+fn a()
+where
+    b: Sized,
+{
+    println!()
+}
diff --git a/tests/crashes/140123-2.rs b/tests/crashes/140123-2.rs
new file mode 100644
index 00000000000..6ed10b9dcc3
--- /dev/null
+++ b/tests/crashes/140123-2.rs
@@ -0,0 +1,12 @@
+//@ known-bug: #140123
+//@ compile-flags: --crate-type lib
+
+trait Trait {}
+
+impl Trait for [(); 0] {}
+
+const ICE: [&mut dyn Trait; 2] = [const { empty_mut() }; 2];
+
+const fn empty_mut() -> &'static mut [(); 0] {
+    &mut []
+}
diff --git a/tests/crashes/140123-3.rs b/tests/crashes/140123-3.rs
new file mode 100644
index 00000000000..a1dcd7fc39f
--- /dev/null
+++ b/tests/crashes/140123-3.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #140123
+//@ compile-flags: --crate-type lib
+
+const ICE: [&mut [()]; 2] = [const { empty_mut() }; 2];
+
+const fn empty_mut() -> &'static mut [()] {
+    unsafe {
+        std::slice::from_raw_parts_mut(std::ptr::dangling_mut(), 0)
+    }
+}
diff --git a/tests/crashes/140123-4.rs b/tests/crashes/140123-4.rs
new file mode 100644
index 00000000000..39042d897ee
--- /dev/null
+++ b/tests/crashes/140123-4.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #140123
+//@ compile-flags: --crate-type lib
+
+const ICE: [&mut [(); 0]; 2] = [const { empty_mut() }; 2];
+
+const fn empty_mut() -> &'static mut [(); 0] {
+    &mut []
+}
+// https://github.com/rust-lang/rust/issues/140123#issuecomment-2820664450
+const ICE2: [&mut [(); 0]; 2] = [const {
+    let x = &mut [];
+    x
+}; 2];
diff --git a/tests/crashes/140123.rs b/tests/crashes/140123.rs
new file mode 100644
index 00000000000..337b5f3cef0
--- /dev/null
+++ b/tests/crashes/140123.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #140123
+//@ compile-flags: --crate-type lib
+
+const OK: [&mut [()]; 2] = [empty_mut(), empty_mut()];
+const ICE: [&mut [()]; 2] = [const { empty_mut() }; 2];
+
+// Any kind of fn call gets around E0764.
+const fn empty_mut() -> &'static mut [()] {
+    &mut []
+}
diff --git a/tests/crashes/140255.rs b/tests/crashes/140255.rs
new file mode 100644
index 00000000000..6b0ec1718b0
--- /dev/null
+++ b/tests/crashes/140255.rs
@@ -0,0 +1,3 @@
+//@ known-bug: #140255
+#[unsafe(macro_use::VAR2)]
+fn dead_code() {}
diff --git a/tests/crashes/140275.rs b/tests/crashes/140275.rs
new file mode 100644
index 00000000000..5ea04af0c8e
--- /dev/null
+++ b/tests/crashes/140275.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #140275
+#![feature(generic_const_exprs)]
+trait T{}
+trait V{}
+impl<const N: i32> T for [i32; N::<&mut V>] {}
diff --git a/tests/crashes/140281.rs b/tests/crashes/140281.rs
new file mode 100644
index 00000000000..76858cfc74a
--- /dev/null
+++ b/tests/crashes/140281.rs
@@ -0,0 +1,18 @@
+//@ known-bug: #140281
+
+macro_rules! foo {
+    ($x:expr) => { $x }
+}
+
+fn main() {
+    let t = vec![
+        /// ‮test⁦ RTL in doc in vec!
+        //  ICE (Sadly)
+        1
+    ];
+
+        foo!(
+        /// ‮test⁦ RTL in doc in macro
+        1
+    );
+}
diff --git a/tests/crashes/140303.rs b/tests/crashes/140303.rs
new file mode 100644
index 00000000000..43a20b5e58e
--- /dev/null
+++ b/tests/crashes/140303.rs
@@ -0,0 +1,22 @@
+//@ known-bug: #140303
+//@compile-flags: -Zvalidate-mir
+use std::future::Future;
+async fn a() -> impl Sized {
+    b(c)
+}
+async fn c(); // kaboom
+fn b<d>(e: d) -> impl Sized
+where
+    d: f,
+{
+    || -> <d>::h { panic!() }
+}
+trait f {
+    type h;
+}
+impl<d, g> f for d
+where
+    d: Fn() -> g,
+    g: Future,
+{
+}
diff --git a/tests/crashes/140333.rs b/tests/crashes/140333.rs
new file mode 100644
index 00000000000..cec1100e6ad
--- /dev/null
+++ b/tests/crashes/140333.rs
@@ -0,0 +1,9 @@
+//@ known-bug: #140333
+fn a() -> impl b<
+    [c; {
+        struct d {
+            #[a]
+            bar: e,
+        }
+    }],
+>;
diff --git a/tests/crashes/140365.rs b/tests/crashes/140365.rs
new file mode 100644
index 00000000000..809ceaf35a0
--- /dev/null
+++ b/tests/crashes/140365.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #140365
+//@compile-flags: -C opt-level=1 -Zvalidate-mir
+fn f() -> &'static str
+where
+    Self: Sized,
+{
+    ""
+}
diff --git a/tests/crashes/140381.rs b/tests/crashes/140381.rs
new file mode 100644
index 00000000000..439ca694d56
--- /dev/null
+++ b/tests/crashes/140381.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #140381
+pub trait Foo<T> {}
+pub trait Lend {
+    type From<'a>
+    where
+        Self: 'a;
+    fn lend(from: Self::From<'_>) -> impl Foo<Self::From<'_>>;
+}
+
+impl<T, F> Lend for (T, F) {
+    type From<'a> = ();
+
+    fn lend(from: Self::From<'_>) -> impl Foo<Self::From<'_>> {
+        from
+    }
+}
diff --git a/tests/crashes/140429.rs b/tests/crashes/140429.rs
new file mode 100644
index 00000000000..041eaf86c5c
--- /dev/null
+++ b/tests/crashes/140429.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #140429
+//@ compile-flags: -Zlint-mir --crate-type lib
+//@ edition:2024
+
+#![feature(async_drop)]
+async fn a<T>(x: T) {}
diff --git a/tests/crashes/140479.rs b/tests/crashes/140479.rs
new file mode 100644
index 00000000000..ed3ca887546
--- /dev/null
+++ b/tests/crashes/140479.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #140479
+macro_rules! a { ( $( { $ [ $b:c ] } )) => ( $(${ concat(d, $b)} ))}
+fn e() {
+    a!({})
+}
diff --git a/tests/crashes/140484.rs b/tests/crashes/140484.rs
new file mode 100644
index 00000000000..92ec1984398
--- /dev/null
+++ b/tests/crashes/140484.rs
@@ -0,0 +1,14 @@
+//@ known-bug: #140484
+//@edition:2024
+#![feature(async_drop)]
+use std::future::AsyncDrop;
+struct a;
+impl Drop for a {
+    fn b() {}
+}
+impl AsyncDrop for a {
+    type c;
+}
+async fn bar() {
+    a;
+}
diff --git a/tests/crashes/140500.rs b/tests/crashes/140500.rs
new file mode 100644
index 00000000000..ee5b93ab821
--- /dev/null
+++ b/tests/crashes/140500.rs
@@ -0,0 +1,14 @@
+//@ known-bug: #140500
+
+#![feature(async_drop)]
+use std::future::AsyncDrop;
+struct a;
+impl Drop for a {
+    fn b() {}
+}
+impl AsyncDrop for a {
+    fn c(d: impl Sized) {}
+}
+async fn bar() {
+    a;
+}
diff --git a/tests/crashes/140530.rs b/tests/crashes/140530.rs
new file mode 100644
index 00000000000..7e0372a4bd8
--- /dev/null
+++ b/tests/crashes/140530.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #140530
+//@ edition: 2024
+
+#![feature(async_drop, gen_blocks)]
+async gen fn a() {
+  _ = async {}
+}
+fn main() {}
diff --git a/tests/crashes/140531.rs b/tests/crashes/140531.rs
new file mode 100644
index 00000000000..f664481d440
--- /dev/null
+++ b/tests/crashes/140531.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #140531
+//@compile-flags: -Zlint-mir --crate-type lib
+//@ edition:2024
+#![feature(async_drop)]
+async fn call_once(f: impl AsyncFnOnce()) {
+    let fut = Box::pin(f());
+}
diff --git a/tests/crashes/140571.rs b/tests/crashes/140571.rs
new file mode 100644
index 00000000000..97fa1d8432d
--- /dev/null
+++ b/tests/crashes/140571.rs
@@ -0,0 +1,14 @@
+//@ known-bug: #140571
+pub trait IsVoid {
+    const IS_VOID: bool;
+}
+impl<T> IsVoid for T {
+    default const IS_VOID: bool = false;
+}
+impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
+
+pub trait NotVoid {}
+impl<T> NotVoid for T where T: IsVoid<IS_VOID = false> + ?Sized {}
+
+pub trait Maybe<T> {}
+impl<T> Maybe<T> for T {}
diff --git a/tests/crashes/140577.rs b/tests/crashes/140577.rs
new file mode 100644
index 00000000000..21e6b1e1522
--- /dev/null
+++ b/tests/crashes/140577.rs
@@ -0,0 +1,32 @@
+//@ known-bug: #140577
+//@ compile-flags: -Znext-solver=globally
+//@ edition:2021
+
+use std::future::Future;
+use std::pin::Pin;
+trait Acquire {
+    type Connection;
+}
+impl Acquire for &'static () {
+    type Connection = ();
+}
+fn b<T: Acquire>() -> impl Future + Send {
+    let x: Pin<Box<dyn Future<Output = T::Connection> + Send>> = todo!();
+    x
+}
+fn main() {
+    async {
+        b::<&()>().await;
+    }
+    .aa();
+}
+
+impl<F> Filter for F where F: Send {}
+
+trait Filter {
+    fn aa(self)
+    where
+        Self: Sized,
+    {
+    }
+}
diff --git a/tests/crashes/140609.rs b/tests/crashes/140609.rs
new file mode 100644
index 00000000000..ee8a4bb3048
--- /dev/null
+++ b/tests/crashes/140609.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #140609
+#![feature(with_negative_coherence)]
+#![feature(generic_const_exprs)]
+#![crate_type = "lib"]
+trait Trait {}
+struct A<const B: bool>;
+
+trait C {}
+
+impl<const D: u32> Trait for E<D> where A<{ D <= 2 }>: FnOnce(&isize) {}
+struct E<const D: u32>;
+
+impl<const D: u32> Trait for E<D> where A<{ D <= 2 }>: C {}
diff --git a/tests/crashes/140683.rs b/tests/crashes/140683.rs
new file mode 100644
index 00000000000..74ea5c2533b
--- /dev/null
+++ b/tests/crashes/140683.rs
@@ -0,0 +1,5 @@
+//@ known-bug: #140683
+impl T {
+#[core::contracts::ensures]
+  fn b() { (loop) }
+}
diff --git a/tests/crashes/140729.rs b/tests/crashes/140729.rs
new file mode 100644
index 00000000000..a436ec58e8e
--- /dev/null
+++ b/tests/crashes/140729.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #140729
+#![feature(min_generic_const_args)]
+
+const C: usize = 0;
+pub struct A<const M: usize> {}
+impl A<C> {
+    fn fun1() {}
+}
+impl A {
+    fn fun1() {}
+}
diff --git a/tests/crashes/140850.rs b/tests/crashes/140850.rs
new file mode 100644
index 00000000000..fd26097deda
--- /dev/null
+++ b/tests/crashes/140850.rs
@@ -0,0 +1,7 @@
+//@ known-bug: #140850
+//@ compile-flags: -Zvalidate-mir
+fn A() -> impl {
+    while A() {}
+    loop {}
+}
+fn main() {}
diff --git a/tests/crashes/140860.rs b/tests/crashes/140860.rs
new file mode 100644
index 00000000000..04da6bd832c
--- /dev/null
+++ b/tests/crashes/140860.rs
@@ -0,0 +1,10 @@
+//@ known-bug: #140860
+#![feature(min_generic_const_args)]
+#![feature(unsized_const_params)]
+#![feature(with_negative_coherence, negative_impls)]
+trait a < const b : &'static str> {} trait c {} struct d< e >(e);
+impl<e> c for e where e: a<""> {}
+impl<e> c for d<e> {}
+impl<e> !a<f> for e {}
+const f : &str = "";
+fn main() {}
diff --git a/tests/crashes/140891.rs b/tests/crashes/140891.rs
new file mode 100644
index 00000000000..421919403ef
--- /dev/null
+++ b/tests/crashes/140891.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #140891
+struct A<const N: usize> {}
+impl<const N: usize> Iterator for A<N> {
+    fn next() -> [(); std::mem::size_of::<Option<Self::Item>>] {}
+}
+fn main() {}
diff --git a/tests/crashes/141124.rs b/tests/crashes/141124.rs
new file mode 100644
index 00000000000..38a2a55e1c4
--- /dev/null
+++ b/tests/crashes/141124.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #141124
+struct S;
+trait SimpleTrait {}
+trait TraitAssoc {
+    type Assoc;
+}
+
+impl<T> TraitAssoc for T
+where
+    T: SimpleTrait,
+{
+    type Assoc = <(T,) as TraitAssoc>::Assoc;
+}
+impl SimpleTrait for <S as TraitAssoc>::Assoc {}
+
+pub fn main() {}
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index 5fc77f95eaf..8afb6ad250e 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,34 +1,34 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
-| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
+| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send
+| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
 | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
 | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
-| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
-| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
+| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
+| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
 | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
-| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
+| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send
+| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
 | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
 | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
-| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
-| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
+| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
+| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
 | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
-| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
+| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send
+| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
 | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
 | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
-| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
-| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
+| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
+| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
 | 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
 | 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
 |
diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
index 6e349a2a24f..744553c7cd2 100644
--- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
+++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
@@ -3,8 +3,8 @@
 | User Type Annotations
 | 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
 | 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
-| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
-| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
+| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
+| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
index d465b8bded2..fa88211383a 100644
--- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
@@ -40,7 +40,7 @@
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0);
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0);
 +     coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:1: 21:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
index cf6d85abd80..9b6d2b22087 100644
--- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
@@ -6,7 +6,7 @@
   
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0);
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0);
-+     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0);
++     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:1: 29:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index 980c5e202ff..b2bb2375aee 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0);
 +     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0);
 +     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0);
-+     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:2: 19:2 (#0);
++     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:9: 17:10 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:19:1: 19:2 (#0);
 + 
       bb0: {
 +         Coverage::VirtualCounter(bcb0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index b707cd41788..2eb78c08ee8 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -10,8 +10,8 @@
       coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
       coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
       coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
-      coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
-      coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
+      coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
+      coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
       coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
   
       bb0: {
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 239b845c231..0c1bc24b6dc 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -10,8 +10,8 @@
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0);
 +     coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
 +     coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
-+     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
-+     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
++     coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:38: 14:39 (#0);
++     coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:1: 15:2 (#0);
 +     coverage Branch { true_bcb: bcb3, false_bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
 + 
       bb0: {
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
index 7f325245bce..d73cc3d214e 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
@@ -45,7 +45,7 @@
           _9 = copy _10;
           _8 = move _9 as *mut i32 (PtrToPtr);
           StorageDead(_9);
--         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+-         _3 = std::intrinsics::copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
 +         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
index 7f325245bce..d73cc3d214e 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
@@ -45,7 +45,7 @@
           _9 = copy _10;
           _8 = move _9 as *mut i32 (PtrToPtr);
           StorageDead(_9);
--         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+-         _3 = std::intrinsics::copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
 +         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 5afddc5ff73..4e000b05a4b 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -1,9 +1,11 @@
 //@ test-mir-pass: LowerIntrinsics
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(core_intrinsics, intrinsics, rustc_attrs)]
+#![feature(core_intrinsics)]
 #![crate_type = "lib"]
 
+use std::intrinsics::copy_nonoverlapping;
+
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
 pub fn wrapping(a: i32, b: i32) {
     // CHECK-LABEL: fn wrapping(
@@ -153,11 +155,6 @@ pub fn discriminant<T>(t: T) {
     core::intrinsics::discriminant_value(&E::B);
 }
 
-// Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
-#[rustc_nounwind]
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-
 // EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
 pub fn f_copy_nonoverlapping() {
     // CHECK-LABEL: fn f_copy_nonoverlapping(
diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp
index 713b8f541ae..8253603e807 100644
--- a/tests/pretty/autodiff/autodiff_forward.pp
+++ b/tests/pretty/autodiff/autodiff_forward.pp
@@ -31,6 +31,8 @@ pub fn f1(x: &[f64], y: f64) -> f64 {
 
     // We want to make sure that we can use the macro for functions defined inside of functions
 
+    // Make sure we can handle generics
+
     ::core::panicking::panic("not implemented")
 }
 #[rustc_autodiff(Forward, 1, Dual, Const, Dual)]
@@ -181,4 +183,16 @@ pub fn f9() {
         ::core::hint::black_box(<f32>::default())
     }
 }
+#[rustc_autodiff]
+#[inline(never)]
+pub fn f10<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T { *x * *x }
+#[rustc_autodiff(Reverse, 1, Duplicated, Active)]
+#[inline(never)]
+pub fn d_square<T: std::ops::Mul<Output = T> +
+    Copy>(x: &T, dx_0: &mut T, dret: T) -> T {
+    unsafe { asm!("NOP", options(pure, nomem)); };
+    ::core::hint::black_box(f10::<T>(x));
+    ::core::hint::black_box((dx_0, dret));
+    ::core::hint::black_box(f10::<T>(x))
+}
 fn main() {}
diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs
index 5a0660a08e5..ae974f9b4db 100644
--- a/tests/pretty/autodiff/autodiff_forward.rs
+++ b/tests/pretty/autodiff/autodiff_forward.rs
@@ -63,4 +63,10 @@ pub fn f9() {
     }
 }
 
+// Make sure we can handle generics
+#[autodiff(d_square, Reverse, Duplicated, Active)]
+pub fn f10<T: std::ops::Mul<Output = T> + Copy>(x: &T) -> T {
+    *x * *x
+}
+
 fn main() {}
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
index bcaef33344e..7e4344f1c69 100644
--- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
+++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
@@ -30,9 +30,9 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
 #[no_mangle]
 pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
     continue_if!(ap.arg::<c_int>() == -1);
-    continue_if!(ap.arg::<c_char>() == 'A' as c_char);
-    continue_if!(ap.arg::<c_char>() == '4' as c_char);
-    continue_if!(ap.arg::<c_char>() == ';' as c_char);
+    continue_if!(ap.arg::<c_int>() == 'A' as c_int);
+    continue_if!(ap.arg::<c_int>() == '4' as c_int);
+    continue_if!(ap.arg::<c_int>() == ';' as c_int);
     continue_if!(ap.arg::<c_int>() == 0x32);
     continue_if!(ap.arg::<c_int>() == 0x10000001);
     continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!"));
@@ -43,7 +43,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
 pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
     continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
     continue_if!(ap.arg::<c_long>() == 12);
-    continue_if!(ap.arg::<c_char>() == 'a' as c_char);
+    continue_if!(ap.arg::<c_int>() == 'a' as c_int);
     continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
     continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
     continue_if!(ap.arg::<c_int>() == 42);
@@ -55,7 +55,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
 pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
     continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
     continue_if!(ap.arg::<c_int>() == 16);
-    continue_if!(ap.arg::<c_char>() == 'A' as c_char);
+    continue_if!(ap.arg::<c_int>() == 'A' as c_int);
     continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
     ap.with_copy(
         |mut ap| {
@@ -75,7 +75,7 @@ pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
 pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
     continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
     continue_if!(ap.arg::<c_long>() == 12);
-    continue_if!(ap.arg::<c_char>() == 'A' as c_char);
+    continue_if!(ap.arg::<c_int>() == 'A' as c_int);
     continue_if!(ap.arg::<c_longlong>() == 1);
     0
 }
diff --git a/tests/rustdoc-gui/collapse-trait-impl.goml b/tests/rustdoc-gui/collapse-trait-impl.goml
new file mode 100644
index 00000000000..4db02e5239b
--- /dev/null
+++ b/tests/rustdoc-gui/collapse-trait-impl.goml
@@ -0,0 +1,26 @@
+// Checks that individual trait impls can only be collapsed via clicking directly on the summary element
+
+go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
+
+// Collapse the trait impl doc. The actual clickable area is outside the element, hence offset.
+click-with-offset: ("summary:has(#trait-impl-link-in-summary)", {"x": -15, "y": 5})
+assert-attribute-false: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
+click-with-offset: ("summary:has(#trait-impl-link-in-summary)", {"x": -15, "y": 5})
+assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
+
+// Clicks on the text should be ignored
+click: "summary:has(#trait-impl-link-in-summary) > .impl"
+assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
+
+// But links should still work
+click: "summary:has(#trait-impl-link-in-summary) a:has(#trait-impl-link-in-summary)"
+assert-window-property-false: ({"pageYOffset": "0"})
+assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
+
+// As well as clicks on elements within links
+go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
+assert-window-property: ({"pageYOffset": "0"})
+click: "#trait-impl-link-in-summary"
+assert-window-property-false: ({"pageYOffset": "0"})
+assert-attribute: ("details:has(#trait-impl-link-in-summary)", {"open": ""})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index bb0015b8f9c..e8afe8b5687 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -79,6 +79,7 @@ impl Foo {
     pub fn warning2() {}
 }
 
+/// <a href="#implementations"><code id="trait-impl-link-in-summary">A collapsible trait impl with a link</code></a>
 impl AsRef<str> for Foo {
     fn as_ref(&self) -> &str {
         "hello"
diff --git a/tests/rustdoc-js/auxiliary/interner.rs b/tests/rustdoc-js/auxiliary/interner.rs
index e4e4ff6276d..8af3b732ef7 100644
--- a/tests/rustdoc-js/auxiliary/interner.rs
+++ b/tests/rustdoc-js/auxiliary/interner.rs
@@ -18,7 +18,7 @@ pub trait Interner: Sized {
     type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
     type BoundVars: IntoIterator<Item = Self::BoundVar>;
     type BoundVar;
-    type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
+    type CanonicalVarKinds: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarKind<Self>>;
     type Ty: Copy
         + DebugWithInfcx<Self>
         + Hash
@@ -77,7 +77,7 @@ pub trait Interner: Sized {
     type ClosureKind: Copy + Debug + Hash + Eq;
 
     // Required method
-    fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
+    fn mk_canonical_var_kinds(self, kinds: &[CanonicalVarKind<Self>]) -> Self::CanonicalVarKinds;
 }
 
 pub trait DebugWithInfcx<I: Interner>: Debug {
@@ -104,10 +104,6 @@ pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
     fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
 }
 
-pub struct CanonicalVarInfo<I: Interner> {
-    pub kind: CanonicalVarKind<I>,
-}
-
 pub struct CanonicalVarKind<I>(std::marker::PhantomData<I>);
 
 pub struct TyKind<I>(std::marker::PhantomData<I>);
diff --git a/tests/rustdoc-js/looks-like-rustc-interner.js b/tests/rustdoc-js/looks-like-rustc-interner.js
index d6d2764c3ae..7d051194454 100644
--- a/tests/rustdoc-js/looks-like-rustc-interner.js
+++ b/tests/rustdoc-js/looks-like-rustc-interner.js
@@ -3,13 +3,13 @@
 
 const EXPECTED = [
     {
-        'query': 'canonicalvarinfo, intoiterator -> intoiterator',
+        'query': 'CanonicalVarKind, intoiterator -> intoiterator',
         'others': [],
     },
     {
-        'query': '[canonicalvarinfo], interner<tys=intoiterator> -> intoiterator',
+        'query': '[CanonicalVarKind], interner<tys=intoiterator> -> intoiterator',
         'others': [
-            { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' },
+            { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_kinds' },
         ],
     },
 ];
diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs
new file mode 100644
index 00000000000..74f5f36f03f
--- /dev/null
+++ b/tests/rustdoc-json/attrs/inline.rs
@@ -0,0 +1,11 @@
+//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[inline]"]'
+#[inline]
+pub fn just_inline() {}
+
+//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[inline(always)]"]'
+#[inline(always)]
+pub fn inline_always() {}
+
+//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[inline(never)]"]'
+#[inline(never)]
+pub fn inline_never() {}
diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs
index 0e8e2ef0d83..6fe29c5eac0 100644
--- a/tests/rustdoc-json/attrs/repr_combination.rs
+++ b/tests/rustdoc-json/attrs/repr_combination.rs
@@ -77,3 +77,7 @@ pub enum AlignedExplicitRepr {
 pub enum ReorderedAlignedExplicitRepr {
     First,
 }
+
+//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]'
+#[repr(transparent)]
+pub struct Transparent(i64);
diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs
deleted file mode 100644
index 1e634ca901d..00000000000
--- a/tests/rustdoc-json/attrs/repr_transparent.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#![no_std]
-
-// Rustdoc JSON *only* includes `#[repr(transparent)]`
-// if the transparency is public API:
-// - if a non-1-ZST field exists, it has to be public
-// - otherwise, all fields are 1-ZST and at least one of them is public
-//
-// More info: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
-
-// Here, the non-1-ZST field is public.
-// We expect `#[repr(transparent)]` in the attributes.
-//
-//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]'
-#[repr(transparent)]
-pub struct Transparent(pub i64);
-
-// Here the non-1-ZST field isn't public, so the attribute isn't included.
-//
-//@ has "$.index[?(@.name=='TransparentNonPub')]"
-//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '[]'
-#[repr(transparent)]
-pub struct TransparentNonPub(i64);
-
-// Only 1-ZST fields here, and one of them is public.
-// We expect `#[repr(transparent)]` in the attributes.
-//
-//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[repr(transparent)]"]'
-#[repr(transparent)]
-pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ());
-
-// Only 1-ZST fields here but none of them are public.
-// The attribute isn't included.
-//
-//@ has "$.index[?(@.name=='AllZstNotPublic')]"
-//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '[]'
-#[repr(transparent)]
-pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ());
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr
new file mode 100644
index 00000000000..113fb7ccb60
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stderr
@@ -0,0 +1,8 @@
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/failed-doctest-extra-semicolon-on-item.rs:11:1
+   |
+11 | /// ```rust
+   | ^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr
new file mode 100644
index 00000000000..d90a289ca69
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stderr
@@ -0,0 +1,14 @@
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/main-alongside-stmts.rs:17:1
+   |
+17 | //! ```
+   | ^^^^^^^
+
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/main-alongside-stmts.rs:26:1
+   |
+26 | //! ```
+   | ^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stderr b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stderr
new file mode 100644
index 00000000000..0dc7c2a2eea
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stderr
@@ -0,0 +1,8 @@
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/test-main-alongside-exprs.rs:15:1
+   |
+15 | //! ```
+   | ^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.rs b/tests/rustdoc-ui/doctest/warn-main-not-called.rs
new file mode 100644
index 00000000000..25d92e9cee9
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/warn-main-not-called.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+//@ compile-flags:--test --test-args --test-threads=1
+//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// In case there is a `main` function in the doctest alongside expressions,
+// the whole doctest will be wrapped into a function and the `main` function
+// won't be called.
+
+//! ```
+//! macro_rules! bla {
+//!     ($($x:tt)*) => {}
+//! }
+//!
+//! let x = 12;
+//! bla!(fn main ());
+//! ```
+//!
+//! ```
+//! let x = 12;
+//! fn main() {}
+//! ```
diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.stderr b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr
new file mode 100644
index 00000000000..3a079f47555
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/warn-main-not-called.stderr
@@ -0,0 +1,14 @@
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/warn-main-not-called.rs:10:1
+   |
+10 | //! ```
+   | ^^^^^^^
+
+warning: the `main` function of this doctest won't be run as it contains expressions at the top level, meaning that the whole doctest code will be wrapped in a function
+  --> $DIR/warn-main-not-called.rs:19:1
+   |
+19 | //! ```
+   | ^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/rustdoc-ui/doctest/warn-main-not-called.stdout b/tests/rustdoc-ui/doctest/warn-main-not-called.stdout
new file mode 100644
index 00000000000..07cdddc7b94
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/warn-main-not-called.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test $DIR/warn-main-not-called.rs - (line 10) ... ok
+test $DIR/warn-main-not-called.rs - (line 19) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/intra-doc/warning.stderr b/tests/rustdoc-ui/intra-doc/warning.stderr
index 3a06f1787e0..9b3f6f822d7 100644
--- a/tests/rustdoc-ui/intra-doc/warning.stderr
+++ b/tests/rustdoc-ui/intra-doc/warning.stderr
@@ -69,29 +69,19 @@ LL | bar [BarC] bar
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarD`
-  --> $DIR/warning.rs:45:9
+  --> $DIR/warning.rs:45:20
    |
 LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    ^^^^ no item named `BarD` in scope
    |
-   = note: the link appears in this line:
-           
-           bar [BarD] bar
-                ^^^^
-   = note: no item named `BarD` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarF`
-  --> $DIR/warning.rs:54:4
+  --> $DIR/warning.rs:54:15
    |
 LL | f!("Foo\nbar [BarF] bar\nbaz");
-   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               ^^^^ no item named `BarF` in scope
    |
-   = note: the link appears in this line:
-           
-           bar [BarF] bar
-                ^^^^
-   = note: no item named `BarF` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
    = note: this warning originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -112,29 +102,19 @@ LL |  * time to introduce a link [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/warning.rs:68:9
+  --> $DIR/warning.rs:68:23
    |
 LL | #[doc = "single line [error]"]
-   |         ^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^ no item named `error` in scope
    |
-   = note: the link appears in this line:
-           
-           single line [error]
-                        ^^^^^
-   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/warning.rs:71:9
+  --> $DIR/warning.rs:71:41
    |
 LL | #[doc = "single line with \"escaping\" [error]"]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                         ^^^^^ no item named `error` in scope
    |
-   = note: the link appears in this line:
-           
-           single line with "escaping" [error]
-                                        ^^^^^
-   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
diff --git a/tests/rustdoc-ui/lints/bare-urls-limit.rs b/tests/rustdoc-ui/lints/bare-urls-limit.rs
new file mode 100644
index 00000000000..f64154b0496
--- /dev/null
+++ b/tests/rustdoc-ui/lints/bare-urls-limit.rs
@@ -0,0 +1,12 @@
+//@ check-fail
+
+#![deny(rustdoc::bare_urls)]
+
+// examples of bare urls that are beyond our ability to generate suggestions for
+
+// this falls through every heuristic in `source_span_for_markdown_range`,
+// and thus does not get any suggestion.
+#[doc = "good: <https://example.com/> \n\n"]
+//~^ ERROR this URL is not a hyperlink
+#[doc = "bad: https://example.com/"]
+pub fn duplicate_raw() {}
diff --git a/tests/rustdoc-ui/lints/bare-urls-limit.stderr b/tests/rustdoc-ui/lints/bare-urls-limit.stderr
new file mode 100644
index 00000000000..9573665cb13
--- /dev/null
+++ b/tests/rustdoc-ui/lints/bare-urls-limit.stderr
@@ -0,0 +1,18 @@
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls-limit.rs:9:9
+   |
+LL |   #[doc = "good: <https://example.com/> \n\n"]
+   |  _________^
+LL | |
+LL | | #[doc = "bad: https://example.com/"]
+   | |___________________________________^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+note: the lint level is defined here
+  --> $DIR/bare-urls-limit.rs:3:9
+   |
+LL | #![deny(rustdoc::bare_urls)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/rustdoc-ui/lints/bare-urls.fixed b/tests/rustdoc-ui/lints/bare-urls.fixed
index 7938d715199..a91573146b8 100644
--- a/tests/rustdoc-ui/lints/bare-urls.fixed
+++ b/tests/rustdoc-ui/lints/bare-urls.fixed
@@ -38,6 +38,16 @@
 //~^ ERROR this URL is not a hyperlink
 pub fn c() {}
 
+#[doc = "here's a thing: <https://example.com/>"]
+//~^ ERROR this URL is not a hyperlink
+pub fn f() {}
+
+/// <https://example.com/sugar>
+//~^ ERROR this URL is not a hyperlink
+#[doc = "<https://example.com/raw>"]
+//~^ ERROR this URL is not a hyperlink
+pub fn mixed() {}
+
 /// <https://somewhere.com>
 /// [a](http://a.com)
 /// [b]
diff --git a/tests/rustdoc-ui/lints/bare-urls.rs b/tests/rustdoc-ui/lints/bare-urls.rs
index 75f42b78ffb..5b008cdafa2 100644
--- a/tests/rustdoc-ui/lints/bare-urls.rs
+++ b/tests/rustdoc-ui/lints/bare-urls.rs
@@ -38,6 +38,16 @@
 //~^ ERROR this URL is not a hyperlink
 pub fn c() {}
 
+#[doc = "here's a thing: https://example.com/"]
+//~^ ERROR this URL is not a hyperlink
+pub fn f() {}
+
+/// https://example.com/sugar
+//~^ ERROR this URL is not a hyperlink
+#[doc = "https://example.com/raw"]
+//~^ ERROR this URL is not a hyperlink
+pub fn mixed() {}
+
 /// <https://somewhere.com>
 /// [a](http://a.com)
 /// [b]
diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr
index ddfc387eaf6..e1108c7e7f8 100644
--- a/tests/rustdoc-ui/lints/bare-urls.stderr
+++ b/tests/rustdoc-ui/lints/bare-urls.stderr
@@ -207,5 +207,41 @@ help: use an automatic link instead
 LL | /// hey! <https://somewhere.com/a?hello=12&bye=11#xyz>
    |          +                                           +
 
-error: aborting due to 17 previous errors
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:41:26
+   |
+LL | #[doc = "here's a thing: https://example.com/"]
+   |                          ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | #[doc = "here's a thing: <https://example.com/>"]
+   |                          +                    +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:45:5
+   |
+LL | /// https://example.com/sugar
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://example.com/sugar>
+   |     +                         +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:47:10
+   |
+LL | #[doc = "https://example.com/raw"]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | #[doc = "<https://example.com/raw>"]
+   |          +                       +
+
+error: aborting due to 20 previous errors
 
diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/unescaped_backticks.stderr
index d93aaf5f3ca..1bcb88e108f 100644
--- a/tests/rustdoc-ui/unescaped_backticks.stderr
+++ b/tests/rustdoc-ui/unescaped_backticks.stderr
@@ -628,10 +628,10 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
    |                                                   +
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:108:9
+  --> $DIR/unescaped_backticks.rs:108:10
    |
 LL | #[doc = "`"]
-   |         ^^^
+   |          ^
    |
    = help: the opening or closing backtick of an inline code may be missing
    = help: if you meant to use a literal backtick, escape it
@@ -639,10 +639,10 @@ LL | #[doc = "`"]
            to this: \`
 
 error: unescaped backtick
-  --> $DIR/unescaped_backticks.rs:115:9
+  --> $DIR/unescaped_backticks.rs:115:26
    |
 LL | #[doc = concat!("\\", "`")]
-   |         ^^^^^^^^^^^^^^^^^^^^
+   |                          ^
    |
    = help: the opening backtick of an inline code may be missing
             change: \`
diff --git a/tests/ui/asm/aarch64/parse-error.rs b/tests/ui/asm/aarch64/parse-error.rs
index 35e1d037f38..622f99aa1b1 100644
--- a/tests/ui/asm/aarch64/parse-error.rs
+++ b/tests/ui/asm/aarch64/parse-error.rs
@@ -1,57 +1,11 @@
 //@ only-aarch64
 
-use std::arch::{asm, global_asm};
+use std::arch::asm;
 
 fn main() {
     let mut foo = 0;
     let mut bar = 0;
     unsafe {
-        asm!();
-        //~^ ERROR requires at least a template string argument
-        asm!(foo);
-        //~^ ERROR asm template must be a string literal
-        asm!("{}" foo);
-        //~^ ERROR expected token: `,`
-        asm!("{}", foo);
-        //~^ ERROR expected operand, clobber_abi, options, or additional template string
-        asm!("{}", in foo);
-        //~^ ERROR expected `(`, found `foo`
-        asm!("{}", in(reg foo));
-        //~^ ERROR expected `)`, found `foo`
-        asm!("{}", in(reg));
-        //~^ ERROR expected expression, found end of macro arguments
-        asm!("{}", inout(=) foo => bar);
-        //~^ ERROR expected register class or explicit register
-        asm!("{}", inout(reg) foo =>);
-        //~^ ERROR expected expression, found end of macro arguments
-        asm!("{}", in(reg) foo => bar);
-        //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
-        asm!("{}", sym foo + bar);
-        //~^ ERROR expected a path for argument to `sym`
-        asm!("", options(foo));
-        //~^ ERROR expected one of
-        asm!("", options(nomem foo));
-        //~^ ERROR expected one of
-        asm!("", options(nomem, foo));
-        //~^ ERROR expected one of
-        asm!("{}", options(), const foo);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("", clobber_abi(foo));
-        //~^ ERROR expected string literal
-        asm!("", clobber_abi("C" foo));
-        //~^ ERROR expected one of `)` or `,`, found `foo`
-        asm!("", clobber_abi("C", foo));
-        //~^ ERROR expected string literal
-        asm!("{}", clobber_abi("C"), const foo);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("", options(), clobber_abi("C"));
-        asm!("{}", options(), clobber_abi("C"), const foo);
-        //~^ ERROR attempt to use a non-constant value in a constant
-        asm!("{a}", a = const foo, a = const bar);
-        //~^ ERROR duplicate argument named `a`
-        //~^^ ERROR argument never used
-        //~^^^ ERROR attempt to use a non-constant value in a constant
-        //~^^^^ ERROR attempt to use a non-constant value in a constant
         asm!("", a = in("x0") foo);
         //~^ ERROR explicit register arguments cannot have names
         asm!("{a}", in("x0") foo, a = const bar);
@@ -61,64 +15,5 @@ fn main() {
         asm!("{1}", in("x0") foo, const bar);
         //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
         //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", options(), "");
-        //~^ ERROR expected one of
-        asm!("{}", in(reg) foo, "{}", out(reg) foo);
-        //~^ ERROR expected one of
-        asm!(format!("{{{}}}", 0), in(reg) foo);
-        //~^ ERROR asm template must be a string literal
-        asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
-        //~^ ERROR asm template must be a string literal
-        asm!("{}", in(reg) _);
-        //~^ ERROR _ cannot be used for input operands
-        asm!("{}", inout(reg) _);
-        //~^ ERROR _ cannot be used for input operands
-        asm!("{}", inlateout(reg) _);
-        //~^ ERROR _ cannot be used for input operands
     }
 }
-
-const FOO: i32 = 1;
-const BAR: i32 = 2;
-global_asm!();
-//~^ ERROR requires at least a template string argument
-global_asm!(FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{}" FOO);
-//~^ ERROR expected token: `,`
-global_asm!("{}", FOO);
-//~^ ERROR expected operand, options, or additional template string
-global_asm!("{}", const);
-//~^ ERROR expected expression, found end of macro arguments
-global_asm!("{}", const(reg) FOO);
-//~^ ERROR expected one of
-global_asm!("", options(FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem, FOO));
-//~^ ERROR expected one of
-global_asm!("{}", options(), const FOO);
-global_asm!("", clobber_abi(FOO));
-//~^ ERROR expected string literal
-global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected one of `)` or `,`, found `FOO`
-global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected string literal
-global_asm!("{}", clobber_abi("C"), const FOO);
-//~^ ERROR `clobber_abi` cannot be used with `global_asm!`
-global_asm!("", options(), clobber_abi("C"));
-//~^ ERROR `clobber_abi` cannot be used with `global_asm!`
-global_asm!("{}", options(), clobber_abi("C"), const FOO);
-//~^ ERROR `clobber_abi` cannot be used with `global_asm!`
-global_asm!("{a}", a = const FOO, a = const BAR);
-//~^ ERROR duplicate argument named `a`
-//~^^ ERROR argument never used
-global_asm!("", options(), "");
-//~^ ERROR expected one of
-global_asm!("{}", const FOO, "{}", const FOO);
-//~^ ERROR expected one of
-global_asm!(format!("{{{}}}", 0), const FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
-//~^ ERROR asm template must be a string literal
diff --git a/tests/ui/asm/aarch64/parse-error.stderr b/tests/ui/asm/aarch64/parse-error.stderr
index 45f9e7989c2..ca21311f87f 100644
--- a/tests/ui/asm/aarch64/parse-error.stderr
+++ b/tests/ui/asm/aarch64/parse-error.stderr
@@ -1,377 +1,19 @@
-error: requires at least a template string argument
-  --> $DIR/parse-error.rs:9:9
-   |
-LL |         asm!();
-   |         ^^^^^^
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:11:14
-   |
-LL |         asm!(foo);
-   |              ^^^
-
-error: expected token: `,`
-  --> $DIR/parse-error.rs:13:19
-   |
-LL |         asm!("{}" foo);
-   |                   ^^^ expected `,`
-
-error: expected operand, clobber_abi, options, or additional template string
-  --> $DIR/parse-error.rs:15:20
-   |
-LL |         asm!("{}", foo);
-   |                    ^^^ expected operand, clobber_abi, options, or additional template string
-
-error: expected `(`, found `foo`
-  --> $DIR/parse-error.rs:17:23
-   |
-LL |         asm!("{}", in foo);
-   |                       ^^^ expected `(`
-
-error: expected `)`, found `foo`
-  --> $DIR/parse-error.rs:19:27
-   |
-LL |         asm!("{}", in(reg foo));
-   |                           ^^^ expected `)`
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:21:27
-   |
-LL |         asm!("{}", in(reg));
-   |                           ^ expected expression
-
-error: expected register class or explicit register
-  --> $DIR/parse-error.rs:23:26
-   |
-LL |         asm!("{}", inout(=) foo => bar);
-   |                          ^
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:25:37
-   |
-LL |         asm!("{}", inout(reg) foo =>);
-   |                                     ^ expected expression
-
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
-  --> $DIR/parse-error.rs:27:32
-   |
-LL |         asm!("{}", in(reg) foo => bar);
-   |                                ^^ expected one of 7 possible tokens
-
-error: expected a path for argument to `sym`
-  --> $DIR/parse-error.rs:29:24
-   |
-LL |         asm!("{}", sym foo + bar);
-   |                        ^^^^^^^^^
-
-error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
-  --> $DIR/parse-error.rs:31:26
-   |
-LL |         asm!("", options(foo));
-   |                          ^^^ expected one of 10 possible tokens
-
-error: expected one of `)` or `,`, found `foo`
-  --> $DIR/parse-error.rs:33:32
-   |
-LL |         asm!("", options(nomem foo));
-   |                                ^^^ expected one of `)` or `,`
-
-error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
-  --> $DIR/parse-error.rs:35:33
-   |
-LL |         asm!("", options(nomem, foo));
-   |                                 ^^^ expected one of 10 possible tokens
-
-error: expected string literal
-  --> $DIR/parse-error.rs:39:30
-   |
-LL |         asm!("", clobber_abi(foo));
-   |                              ^^^ not a string literal
-
-error: expected one of `)` or `,`, found `foo`
-  --> $DIR/parse-error.rs:41:34
-   |
-LL |         asm!("", clobber_abi("C" foo));
-   |                                  ^^^ expected one of `)` or `,`
-
-error: expected string literal
-  --> $DIR/parse-error.rs:43:35
-   |
-LL |         asm!("", clobber_abi("C", foo));
-   |                                   ^^^ not a string literal
-
-error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:50:36
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                     -------------  ^^^^^^^^^^^^^ duplicate argument
-   |                     |
-   |                     previously here
-
-error: argument never used
-  --> $DIR/parse-error.rs:50:36
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                                    ^^^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
 error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:55:18
+  --> $DIR/parse-error.rs:9:18
    |
 LL |         asm!("", a = in("x0") foo);
    |                  ^^^^^^^^^^^^^^^^
 
 error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:61:35
+  --> $DIR/parse-error.rs:15:35
    |
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                     ------------  ^^^^^^^^^ positional argument
    |                     |
    |                     explicit register argument
 
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:64:29
-   |
-LL |         asm!("", options(), "");
-   |                             ^^ expected one of 10 possible tokens
-
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:66:33
-   |
-LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
-   |                                 ^^^^ expected one of 10 possible tokens
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:68:14
-   |
-LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
-   |              ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:70:21
-   |
-LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
-   |                     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:72:28
-   |
-LL |         asm!("{}", in(reg) _);
-   |                            ^
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:74:31
-   |
-LL |         asm!("{}", inout(reg) _);
-   |                               ^
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:76:35
-   |
-LL |         asm!("{}", inlateout(reg) _);
-   |                                   ^
-
-error: requires at least a template string argument
-  --> $DIR/parse-error.rs:83:1
-   |
-LL | global_asm!();
-   | ^^^^^^^^^^^^^
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:85:13
-   |
-LL | global_asm!(FOO);
-   |             ^^^
-
-error: expected token: `,`
-  --> $DIR/parse-error.rs:87:18
-   |
-LL | global_asm!("{}" FOO);
-   |                  ^^^ expected `,`
-
-error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:89:19
-   |
-LL | global_asm!("{}", FOO);
-   |                   ^^^ expected operand, options, or additional template string
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:91:24
-   |
-LL | global_asm!("{}", const);
-   |                        ^ expected expression
-
-error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
-  --> $DIR/parse-error.rs:93:30
-   |
-LL | global_asm!("{}", const(reg) FOO);
-   |                              ^^^ expected one of `,`, `.`, `?`, or an operator
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
-  --> $DIR/parse-error.rs:95:25
-   |
-LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)` or `,`, found `FOO`
-  --> $DIR/parse-error.rs:97:31
-   |
-LL | global_asm!("", options(nomem FOO));
-   |                               ^^^ expected one of `)` or `,`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
-  --> $DIR/parse-error.rs:99:32
-   |
-LL | global_asm!("", options(nomem, FOO));
-   |                                ^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected string literal
-  --> $DIR/parse-error.rs:102:29
-   |
-LL | global_asm!("", clobber_abi(FOO));
-   |                             ^^^ not a string literal
-
-error: expected one of `)` or `,`, found `FOO`
-  --> $DIR/parse-error.rs:104:33
-   |
-LL | global_asm!("", clobber_abi("C" FOO));
-   |                                 ^^^ expected one of `)` or `,`
-
-error: expected string literal
-  --> $DIR/parse-error.rs:106:34
-   |
-LL | global_asm!("", clobber_abi("C", FOO));
-   |                                  ^^^ not a string literal
-
-error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:108:19
-   |
-LL | global_asm!("{}", clobber_abi("C"), const FOO);
-   |                   ^^^^^^^^^^^^^^^^
-
-error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:110:28
-   |
-LL | global_asm!("", options(), clobber_abi("C"));
-   |                            ^^^^^^^^^^^^^^^^
-
-error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:112:30
-   |
-LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
-   |                              ^^^^^^^^^^^^^^^^
-
-error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:114:35
-   |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
-   |                    -------------  ^^^^^^^^^^^^^ duplicate argument
-   |                    |
-   |                    previously here
-
-error: argument never used
-  --> $DIR/parse-error.rs:114:35
-   |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
-   |                                   ^^^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
-error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:117:28
-   |
-LL | global_asm!("", options(), "");
-   |                            ^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
-
-error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:119:30
-   |
-LL | global_asm!("{}", const FOO, "{}", const FOO);
-   |                              ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym`
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:121:13
-   |
-LL | global_asm!(format!("{{{}}}", 0), const FOO);
-   |             ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:123:20
-   |
-LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
-   |                    ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:37:37
-   |
-LL |         asm!("{}", options(), const foo);
-   |                                     ^^^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL -     let mut foo = 0;
-LL +     const foo: /* Type */ = 0;
-   |
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:45:44
-   |
-LL |         asm!("{}", clobber_abi("C"), const foo);
-   |                                            ^^^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL -     let mut foo = 0;
-LL +     const foo: /* Type */ = 0;
-   |
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:48:55
-   |
-LL |         asm!("{}", options(), clobber_abi("C"), const foo);
-   |                                                       ^^^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL -     let mut foo = 0;
-LL +     const foo: /* Type */ = 0;
-   |
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:50:31
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                               ^^^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL -     let mut foo = 0;
-LL +     const foo: /* Type */ = 0;
-   |
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:50:46
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                                              ^^^ non-constant value
-   |
-help: consider using `const` instead of `let`
-   |
-LL -     let mut bar = 0;
-LL +     const bar: /* Type */ = 0;
-   |
-
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:57:45
+  --> $DIR/parse-error.rs:11:45
    |
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
@@ -383,7 +25,7 @@ LL +     const bar: /* Type */ = 0;
    |
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:59:45
+  --> $DIR/parse-error.rs:13:45
    |
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
@@ -395,7 +37,7 @@ LL +     const bar: /* Type */ = 0;
    |
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:61:41
+  --> $DIR/parse-error.rs:15:41
    |
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                                         ^^^ non-constant value
@@ -406,6 +48,6 @@ LL -     let mut bar = 0;
 LL +     const bar: /* Type */ = 0;
    |
 
-error: aborting due to 57 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
index a8256f775a6..19b63a041d6 100644
--- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
+++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
@@ -27,7 +27,7 @@ LL |         B::X => println!("B::X"),
    |         ^^^^ `const` depends on a generic parameter
 
 error[E0158]: constant pattern cannot depend on generic parameters
-  --> $DIR/associated-const-type-parameter-pattern.rs:30:9
+  --> $DIR/associated-const-type-parameter-pattern.rs:28:48
    |
 LL | pub trait Foo {
    | -------------
@@ -35,13 +35,12 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
-   |                     - constant depends on this generic parameter
-LL |
-LL |     let A::X = arg;
-   |         ^^^^ `const` depends on a generic parameter
+   |                     -                          ^^^^ `const` depends on a generic parameter
+   |                     |
+   |                     constant depends on this generic parameter
 
 error[E0158]: constant pattern cannot depend on generic parameters
-  --> $DIR/associated-const-type-parameter-pattern.rs:28:48
+  --> $DIR/associated-const-type-parameter-pattern.rs:30:9
    |
 LL | pub trait Foo {
    | -------------
@@ -49,9 +48,10 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
-   |                     -                          ^^^^ `const` depends on a generic parameter
-   |                     |
-   |                     constant depends on this generic parameter
+   |                     - constant depends on this generic parameter
+LL |
+LL |     let A::X = arg;
+   |         ^^^^ `const` depends on a generic parameter
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
index 978305c2ce3..3e914e0538d 100644
--- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
+++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12
    |
 LL |     let _: S::<bool>::Pr = ();
-   |            ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<S<bool> as Tr>::Pr`
+   |            ^^^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::<bool>::Pr = ();
+LL +     let _: <S<bool> as Tr>::Pr = ();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
index 9e1dd739807..fcf6b4c3e73 100644
--- a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
+++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/ambiguous-associated-type-with-generics.rs:13:13
    |
 LL |     let _x: <dyn Trait<i32>>::Ty;
-   |             ^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<dyn Trait<i32> as Assoc>::Ty`
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL |     let _x: <dyn Trait<i32> as Assoc>::Ty;
+   |                             ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
index a2346e292ac..84a9da09988 100644
--- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
+++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr
@@ -13,7 +13,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-item-duplicate-names-3.rs:18:12
    |
 LL |     let x: Baz::Bar = 5;
-   |            ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Foo>::Bar`
+   |            ^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let x: Baz::Bar = 5;
+LL +     let x: <Baz as Foo>::Bar = 5;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
index aad6dfc496b..a13fdbda1bf 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr
@@ -7,7 +7,7 @@ LL |     Trait::method(..): Send,
 help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
    |
 LL -     Trait::method(..): Send,
-LL +     <Example as Trait>::method: Send,
+LL +     <Example as Trait>::method(..): Send,
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
index 38202bdbf07..4c4c2c24079 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr
@@ -3,18 +3,35 @@ error[E0223]: ambiguous associated function
    |
 LL |     <()>::method(..): Send,
    |     ^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `()`, you could use the fully-qualified path
+   |
+LL |     <() as Example>::method(..): Send,
+   |         ++++++++++
 
 error[E0223]: ambiguous associated function
   --> $DIR/path-non-param-qself.rs:13:5
    |
 LL |     i32::method(..): Send,
    |     ^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `i32`, you could use the fully-qualified path
+   |
+LL -     i32::method(..): Send,
+LL +     <i32 as Example>::method(..): Send,
+   |
 
 error[E0223]: ambiguous associated function
   --> $DIR/path-non-param-qself.rs:15:5
    |
 LL |     Adt::method(..): Send,
    |     ^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated function `method` implemented for `Adt`, you could use the fully-qualified path
+   |
+LL -     Adt::method(..): Send,
+LL +     <Adt as Example>::method(..): Send,
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index 1be8db5ddf4..a7647cf26aa 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -14,7 +14,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:22:17
    |
 LL | trait Foo where Foo::Assoc: Bar {
-   |                 ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc`
+   |                 ^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL - trait Foo where Foo::Assoc: Bar {
+LL + trait Foo where <Self as Foo>::Assoc: Bar {
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:27:10
@@ -42,7 +48,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:13:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+   |                       ^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     fn grab(&self) -> Grab::Value;
+LL +     fn grab(&self) -> <Self as Grab>::Value;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:16:22
diff --git a/tests/ui/async-await/async-closures/async-fn-mut-impl-fn-once.rs b/tests/ui/async-await/async-closures/async-fn-mut-impl-fn-once.rs
new file mode 100644
index 00000000000..59d034953d7
--- /dev/null
+++ b/tests/ui/async-await/async-closures/async-fn-mut-impl-fn-once.rs
@@ -0,0 +1,15 @@
+//@ edition:2021
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+fn call_once<F>(_: impl FnOnce() -> F) {}
+
+fn main() {
+    let mut i = 0;
+    let c = async || {
+        i += 1;
+    };
+    call_once(c);
+}
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.rs b/tests/ui/async-await/async-drop/dependency-dropped.rs
index f763bb32b17..d7f415e19aa 100644
--- a/tests/ui/async-await/async-drop/dependency-dropped.rs
+++ b/tests/ui/async-await/async-drop/dependency-dropped.rs
@@ -1,9 +1,12 @@
 //@ run-pass
 //@ check-run-results
+//@ revisions: with_feature without_feature
 //@ aux-build:async-drop-dep.rs
 //@ edition:2021
 
-#![feature(async_drop)]
+#![cfg_attr(with_feature, feature(async_drop))]
+//[without_feature]~^ WARN found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
+
 #![allow(incomplete_features)]
 
 extern crate async_drop_dep;
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.run.stdout b/tests/ui/async-await/async-drop/dependency-dropped.with_feature.run.stdout
index 7aaf70c12d6..7aaf70c12d6 100644
--- a/tests/ui/async-await/async-drop/dependency-dropped.run.stdout
+++ b/tests/ui/async-await/async-drop/dependency-dropped.with_feature.run.stdout
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout
new file mode 100644
index 00000000000..80eeeefc222
--- /dev/null
+++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.run.stdout
@@ -0,0 +1 @@
+Sync drop
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr
new file mode 100644
index 00000000000..96a4572055c
--- /dev/null
+++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr
@@ -0,0 +1,10 @@
+warning: found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
+  --> $DIR/dependency-dropped.rs:7:1
+   |
+LL | #![cfg_attr(with_feature, feature(async_drop))]
+   | ^
+   |
+   = help: if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/async-await/async-drop/deref-later-projection.rs b/tests/ui/async-await/async-drop/deref-later-projection.rs
new file mode 100644
index 00000000000..baf81daf766
--- /dev/null
+++ b/tests/ui/async-await/async-drop/deref-later-projection.rs
@@ -0,0 +1,26 @@
+// Ex-ICE: #140975
+//@ compile-flags: -Zvalidate-mir
+//@ build-pass
+//@ edition:2021
+#![crate_type = "lib"]
+#![feature(async_drop)]
+#![allow(incomplete_features)]
+
+use std::{future::AsyncDrop, pin::Pin};
+
+struct HasAsyncDrop ;
+impl Drop for HasAsyncDrop {
+    fn drop(&mut self) {}
+}
+impl AsyncDrop for HasAsyncDrop {
+    async fn drop(self: Pin<&mut Self>) {}
+}
+
+struct Holder {
+    inner: HasAsyncDrop,
+}
+async fn bar() {
+    Holder {
+        inner: HasAsyncDrop
+   };
+}
diff --git a/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs
new file mode 100644
index 00000000000..bd0a95eb1e4
--- /dev/null
+++ b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.rs
@@ -0,0 +1,17 @@
+//@ edition: 2024
+// Ex-ICE: #140974
+#![crate_type = "lib"]
+#![allow(incomplete_features)]
+#![feature(async_drop)]
+use core::future::AsyncDrop;
+
+async fn fun(_: HasIncompleteAsyncDrop) {}
+
+struct HasIncompleteAsyncDrop;
+impl Drop for HasIncompleteAsyncDrop {
+    fn drop(&mut self) {}
+}
+impl AsyncDrop for HasIncompleteAsyncDrop {
+    //~^ ERROR: not all trait items implemented, missing: `drop` [E0046]
+    // not implemented yet..
+}
diff --git a/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr
new file mode 100644
index 00000000000..d8582398c79
--- /dev/null
+++ b/tests/ui/async-await/async-drop/elaborate-index-out-of-bounds.stderr
@@ -0,0 +1,11 @@
+error[E0046]: not all trait items implemented, missing: `drop`
+  --> $DIR/elaborate-index-out-of-bounds.rs:14:1
+   |
+LL | impl AsyncDrop for HasIncompleteAsyncDrop {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation
+   |
+   = help: implement the missing item: `async fn drop(self: Pin<&mut Self>) { todo!() }`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/async-await/async-drop/open-drop-error2.rs b/tests/ui/async-await/async-drop/open-drop-error2.rs
new file mode 100644
index 00000000000..b2a7b68190e
--- /dev/null
+++ b/tests/ui/async-await/async-drop/open-drop-error2.rs
@@ -0,0 +1,21 @@
+//@compile-flags: -Zvalidate-mir -Zinline-mir=yes --crate-type=lib
+
+#![feature(async_drop)]
+#![allow(incomplete_features)]
+
+use std::{
+    future::{Future, async_drop_in_place},
+    pin::pin,
+    task::Context,
+};
+
+fn wrong() -> impl Sized {
+    //~^ ERROR: the size for values of type `str` cannot be known at compilation time
+    *"abc" // Doesn't implement Sized
+}
+fn weird(context: &mut Context<'_>) {
+    let mut e = wrong();
+    let h = unsafe { async_drop_in_place(&raw mut e) };
+    let i = pin!(h);
+    i.poll(context);
+}
diff --git a/tests/ui/async-await/async-drop/open-drop-error2.stderr b/tests/ui/async-await/async-drop/open-drop-error2.stderr
new file mode 100644
index 00000000000..e849829b1c7
--- /dev/null
+++ b/tests/ui/async-await/async-drop/open-drop-error2.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/open-drop-error2.rs:12:15
+   |
+LL | fn wrong() -> impl Sized {
+   |               ^^^^^^^^^^ doesn't have a size known at compile-time
+LL |
+LL |     *"abc" // Doesn't implement Sized
+   |     ------ return type was inferred to be `str` here
+   |
+   = help: the trait `Sized` is not implemented for `str`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     *"abc" // Doesn't implement Sized
+LL +     "abc" // Doesn't implement Sized
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr
index bf20473924b..07c3fd3527f 100644
--- a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr
+++ b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr
@@ -42,30 +42,6 @@ LL |     async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output;
    = help: consider moving `async_dispatch` to another trait
    = note: required for the cast from `Pin<&mut {async block@$DIR/mut-is-pointer-like.rs:32:32: 32:37}>` to `Pin<&mut dyn AsyncTrait<Output = ()>>`
 
-error[E0277]: the trait bound `dyn AsyncTrait<Output = ()>: AsyncTrait` is not satisfied
-  --> $DIR/mut-is-pointer-like.rs:36:11
-   |
-LL |         x.async_dispatch().await;
-   |           ^^^^^^^^^^^^^^ the trait `AsyncTrait` is not implemented for `dyn AsyncTrait<Output = ()>`
-
-error[E0038]: the trait `AsyncTrait` is not dyn compatible
-  --> $DIR/mut-is-pointer-like.rs:36:9
-   |
-LL |         x.async_dispatch().await;
-   |         ^^^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mut-is-pointer-like.rs:16:14
-   |
-LL | trait AsyncTrait {
-   |       ---------- this trait is not dyn compatible...
-...
-LL |     async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output;
-   |              ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async`
-   = help: consider moving `async_dispatch` to another trait
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0038, E0277.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/async-await/dyn/works.stderr b/tests/ui/async-await/dyn/works.stderr
index 47abeab5aac..1fe2b28eca8 100644
--- a/tests/ui/async-await/dyn/works.stderr
+++ b/tests/ui/async-await/dyn/works.stderr
@@ -42,40 +42,6 @@ LL |     async fn async_dispatch(&self);
    = help: consider moving `async_dispatch` to another trait
    = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead.
 
-error[E0038]: the trait `AsyncTrait` is not dyn compatible
-  --> $DIR/works.rs:28:11
-   |
-LL |         x.async_dispatch().await;
-   |           ^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/works.rs:14:14
-   |
-LL | trait AsyncTrait {
-   |       ---------- this trait is not dyn compatible...
-LL |     async fn async_dispatch(&self);
-   |              ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async`
-   = help: consider moving `async_dispatch` to another trait
-   = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead.
-
-error[E0038]: the trait `AsyncTrait` is not dyn compatible
-  --> $DIR/works.rs:28:9
-   |
-LL |         x.async_dispatch().await;
-   |         ^^^^^^^^^^^^^^^^^^ `AsyncTrait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/works.rs:14:14
-   |
-LL | trait AsyncTrait {
-   |       ---------- this trait is not dyn compatible...
-LL |     async fn async_dispatch(&self);
-   |              ^^^^^^^^^^^^^^ ...because method `async_dispatch` is `async`
-   = help: consider moving `async_dispatch` to another trait
-   = help: only type `&'static str` implements `AsyncTrait`; consider using it directly instead.
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/async-await/format-await-send.rs b/tests/ui/async-await/format-await-send.rs
new file mode 100644
index 00000000000..13ae7233fd6
--- /dev/null
+++ b/tests/ui/async-await/format-await-send.rs
@@ -0,0 +1,24 @@
+// regression test for <https://github.com/rust-lang/rust/issues/101650>
+// assert that Future which has format!() with an async function is Send
+
+#![allow(unused)]
+
+//@ check-pass
+//@ edition: 2018
+
+use core::future::Future;
+use core::pin::Pin;
+
+fn build_string() -> Pin<Box<dyn Future<Output = String> + Send>> {
+    Box::pin(async move {
+        let mut string_builder = String::new();
+        string_builder += &format!("Hello {}", helper().await);
+        string_builder
+    })
+}
+
+async fn helper() -> String {
+    "World".to_string()
+}
+
+fn main() {}
diff --git a/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs b/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs
new file mode 100644
index 00000000000..4c06d0fdfe3
--- /dev/null
+++ b/tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs
@@ -0,0 +1,24 @@
+#[doc(alias="DocAliasS1")]
+pub struct S1;
+
+#[doc(alias="DocAliasS2")]
+#[doc(alias("DocAliasS3", "DocAliasS4"))]
+pub struct S2;
+
+#[doc(alias("doc_alias_f1", "doc_alias_f2"))]
+pub fn f() {}
+
+pub mod m {
+    #[doc(alias="DocAliasS5")]
+    pub struct S5;
+
+    pub mod n {
+        #[doc(alias("DocAliasX"))]
+        pub mod x {
+            pub mod y {
+                #[doc(alias="DocAliasS6")]
+                pub struct S6;
+            }
+        }
+    }
+}
diff --git a/tests/ui/attributes/use-doc-alias-name.rs b/tests/ui/attributes/use-doc-alias-name.rs
new file mode 100644
index 00000000000..1fc9199b6e3
--- /dev/null
+++ b/tests/ui/attributes/use-doc-alias-name.rs
@@ -0,0 +1,67 @@
+//@ aux-build: use-doc-alias-name-extern.rs
+
+// issue#124273
+
+extern crate use_doc_alias_name_extern;
+
+use use_doc_alias_name_extern::*;
+
+#[doc(alias="LocalDocAliasS")]
+struct S;
+
+fn main() {
+    LocalDocAliasS; // don't show help in local crate
+    //~^ ERROR: cannot find value `LocalDocAliasS` in this scope
+
+    DocAliasS1;
+    //~^ ERROR: cannot find value `DocAliasS1` in this scope
+    //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+
+    DocAliasS2;
+    //~^ ERROR: cannot find value `DocAliasS2` in this scope
+    //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
+
+    DocAliasS3;
+    //~^ ERROR: cannot find value `DocAliasS3` in this scope
+    //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
+
+    DocAliasS4;
+    //~^ ERROR: cannot find value `DocAliasS4` in this scope
+    //~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
+
+    doc_alias_f1();
+    //~^ ERROR: cannot find function `doc_alias_f1` in this scope
+    //~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
+
+    doc_alias_f2();
+    //~^ ERROR: cannot find function `doc_alias_f2` in this scope
+    //~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
+
+    m::DocAliasS5;
+    //~^ ERROR: cannot find value `DocAliasS5` in module `m`
+    //~| HELP: `S5` has a name defined in the doc alias attribute as `DocAliasS5`
+
+    not_exist_module::DocAliasS1;
+    //~^ ERROR: use of unresolved module or unlinked crate `not_exist_module`
+    //~| HELP: you might be missing a crate named `not_exist_module`
+
+    use_doc_alias_name_extern::DocAliasS1;
+    //~^ ERROR: cannot find value `DocAliasS1` in crate `use_doc_alias_name_extern
+    //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+
+    m::n::DocAliasX::y::S6;
+    //~^ ERROR: could not find `DocAliasX` in `n`
+    //~| HELP: `x` has a name defined in the doc alias attribute as `DocAliasX`
+
+    m::n::x::y::DocAliasS6;
+    //~^ ERROR: cannot find value `DocAliasS6` in module `m::n::x::y`
+    //~| HELP: `S6` has a name defined in the doc alias attribute as `DocAliasS6`
+}
+
+trait T {
+    fn f() {
+        DocAliasS1;
+        //~^ ERROR: cannot find value `DocAliasS1` in this scope
+        //~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+    }
+}
diff --git a/tests/ui/attributes/use-doc-alias-name.stderr b/tests/ui/attributes/use-doc-alias-name.stderr
new file mode 100644
index 00000000000..07f4865e415
--- /dev/null
+++ b/tests/ui/attributes/use-doc-alias-name.stderr
@@ -0,0 +1,150 @@
+error[E0433]: failed to resolve: could not find `DocAliasX` in `n`
+  --> $DIR/use-doc-alias-name.rs:52:11
+   |
+LL |     m::n::DocAliasX::y::S6;
+   |           ^^^^^^^^^ could not find `DocAliasX` in `n`
+   |
+help: `x` has a name defined in the doc alias attribute as `DocAliasX`
+   |
+LL -     m::n::DocAliasX::y::S6;
+LL +     m::n::x::y::S6;
+   |
+
+error[E0425]: cannot find value `LocalDocAliasS` in this scope
+  --> $DIR/use-doc-alias-name.rs:13:5
+   |
+LL |     LocalDocAliasS; // don't show help in local crate
+   |     ^^^^^^^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `DocAliasS1` in this scope
+  --> $DIR/use-doc-alias-name.rs:16:5
+   |
+LL |     DocAliasS1;
+   |     ^^^^^^^^^^
+   |
+help: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+   |
+LL -     DocAliasS1;
+LL +     S1;
+   |
+
+error[E0425]: cannot find value `DocAliasS2` in this scope
+  --> $DIR/use-doc-alias-name.rs:20:5
+   |
+LL |     DocAliasS2;
+   |     ^^^^^^^^^^
+   |
+help: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
+   |
+LL -     DocAliasS2;
+LL +     S2;
+   |
+
+error[E0425]: cannot find value `DocAliasS3` in this scope
+  --> $DIR/use-doc-alias-name.rs:24:5
+   |
+LL |     DocAliasS3;
+   |     ^^^^^^^^^^
+   |
+help: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
+   |
+LL -     DocAliasS3;
+LL +     S2;
+   |
+
+error[E0425]: cannot find value `DocAliasS4` in this scope
+  --> $DIR/use-doc-alias-name.rs:28:5
+   |
+LL |     DocAliasS4;
+   |     ^^^^^^^^^^
+   |
+help: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
+   |
+LL -     DocAliasS4;
+LL +     S2;
+   |
+
+error[E0425]: cannot find value `DocAliasS5` in module `m`
+  --> $DIR/use-doc-alias-name.rs:40:8
+   |
+LL |     m::DocAliasS5;
+   |        ^^^^^^^^^^
+   |
+help: `S5` has a name defined in the doc alias attribute as `DocAliasS5`
+   |
+LL -     m::DocAliasS5;
+LL +     m::S5;
+   |
+
+error[E0425]: cannot find value `DocAliasS1` in crate `use_doc_alias_name_extern`
+  --> $DIR/use-doc-alias-name.rs:48:32
+   |
+LL |     use_doc_alias_name_extern::DocAliasS1;
+   |                                ^^^^^^^^^^
+   |
+help: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+   |
+LL -     use_doc_alias_name_extern::DocAliasS1;
+LL +     use_doc_alias_name_extern::S1;
+   |
+
+error[E0425]: cannot find value `DocAliasS6` in module `m::n::x::y`
+  --> $DIR/use-doc-alias-name.rs:56:17
+   |
+LL |     m::n::x::y::DocAliasS6;
+   |                 ^^^^^^^^^^
+   |
+help: `S6` has a name defined in the doc alias attribute as `DocAliasS6`
+   |
+LL -     m::n::x::y::DocAliasS6;
+LL +     m::n::x::y::S6;
+   |
+
+error[E0425]: cannot find value `DocAliasS1` in this scope
+  --> $DIR/use-doc-alias-name.rs:63:9
+   |
+LL |         DocAliasS1;
+   |         ^^^^^^^^^^
+   |
+help: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
+   |
+LL -         DocAliasS1;
+LL +         S1;
+   |
+
+error[E0425]: cannot find function `doc_alias_f1` in this scope
+  --> $DIR/use-doc-alias-name.rs:32:5
+   |
+LL |     doc_alias_f1();
+   |     ^^^^^^^^^^^^
+   |
+help: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
+   |
+LL -     doc_alias_f1();
+LL +     f();
+   |
+
+error[E0425]: cannot find function `doc_alias_f2` in this scope
+  --> $DIR/use-doc-alias-name.rs:36:5
+   |
+LL |     doc_alias_f2();
+   |     ^^^^^^^^^^^^
+   |
+help: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
+   |
+LL -     doc_alias_f2();
+LL +     f();
+   |
+
+error[E0433]: failed to resolve: use of unresolved module or unlinked crate `not_exist_module`
+  --> $DIR/use-doc-alias-name.rs:44:5
+   |
+LL |     not_exist_module::DocAliasS1;
+   |     ^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `not_exist_module`
+   |
+   = help: you might be missing a crate named `not_exist_module`
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0425, E0433.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs
new file mode 100644
index 00000000000..4fdf5470fea
--- /dev/null
+++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs
@@ -0,0 +1,22 @@
+// Regression test for #122704
+use std::any::Any;
+
+pub struct Foo {
+    bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>,
+}
+
+impl Foo {
+    pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+        self.bar = Box::new(|baz| Box::new(f(baz)));
+        //~^ ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+        //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+        //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+        //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+        //~| ERROR the parameter type `I` may not live long enough
+        //~| ERROR the parameter type `I` may not live long enough
+        //~| ERROR the parameter type `I` may not live long enough
+        //~| ERROR `f` does not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr
new file mode 100644
index 00000000000..df86ce79f09
--- /dev/null
+++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr
@@ -0,0 +1,119 @@
+error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |         ^^^^^^^^
+   |         |
+   |         the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
+   |         ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
+   |                                                                      +++++++++
+
+error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |         ^^^^^^^^
+   |         |
+   |         the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
+   |         ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
+   |                                                                      +++++++++
+
+error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |                    ^^^^^^^^
+   |                    |
+   |                    the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
+   |                    ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
+   |                                                                      +++++++++
+
+error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
+   |                    ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
+   |                                                                      +++++++++
+
+error[E0310]: the parameter type `I` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |                                   ^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   the parameter type `I` must be valid for the static lifetime...
+   |                                   ...so that the type `I` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+   |                 +++++++++
+
+error[E0310]: the parameter type `I` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
+   |
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |                                   ^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   the parameter type `I` must be valid for the static lifetime...
+   |                                   ...so that the type `I` will meet its required lifetime bounds
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+   |                 +++++++++
+
+error[E0311]: the parameter type `I` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+   |                   --------- the parameter type `I` must be valid for the anonymous lifetime defined here...
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |                                   ^^^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL |     pub fn ack<'a, I: 'a>(&'a mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+   |                +++  ++++   ++
+
+error[E0597]: `f` does not live long enough
+  --> $DIR/unconstrained-closure-lifetime-generic.rs:10:44
+   |
+LL |     pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
+   |                              - binding `f` declared here
+LL |         self.bar = Box::new(|baz| Box::new(f(baz)));
+   |         --------            -----          ^ borrowed value does not live long enough
+   |         |                   |
+   |         |                   value captured here
+   |         coercion requires that `f` is borrowed for `'static`
+...
+LL |     }
+   |     - `f` dropped here while still borrowed
+   |
+   = note: due to object lifetime defaults, `Box<dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)>>` actually means `Box<(dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)> + 'static)>`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0310, E0311, E0597.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs
new file mode 100644
index 00000000000..3eee98d9bdb
--- /dev/null
+++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs
@@ -0,0 +1,11 @@
+// Regression test for #139004
+use std::any::Any;
+
+type B = Box<dyn for<'a> Fn(&(dyn Any + 'a)) -> Box<dyn Any + 'a>>;
+
+fn foo<E>() -> B {
+    Box::new(|e| Box::new(e.is::<E>()))
+    //~^ ERROR the parameter type `E` may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr
new file mode 100644
index 00000000000..c9d5f78828d
--- /dev/null
+++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr
@@ -0,0 +1,17 @@
+error[E0310]: the parameter type `E` may not live long enough
+  --> $DIR/unconstrained-closure-lifetime-trait-object.rs:7:29
+   |
+LL |     Box::new(|e| Box::new(e.is::<E>()))
+   |                             ^^
+   |                             |
+   |                             the parameter type `E` must be valid for the static lifetime...
+   |                             ...so that the type `E` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound
+   |
+LL | fn foo<E: 'static>() -> B {
+   |         +++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/tests/ui/check-cfg/wrong-version-syntax.fixed b/tests/ui/check-cfg/wrong-version-syntax.fixed
new file mode 100644
index 00000000000..efbe2ed1bd8
--- /dev/null
+++ b/tests/ui/check-cfg/wrong-version-syntax.fixed
@@ -0,0 +1,14 @@
+// Check warning for wrong `cfg(version("1.27"))` syntax
+//
+//@ check-pass
+//@ no-auto-check-cfg
+//@ compile-flags: --check-cfg=cfg()
+//@ run-rustfix
+
+#![feature(cfg_version)]
+
+#[cfg(not(version("1.48.0")))]
+//~^ WARNING unexpected `cfg` condition name: `version`
+pub fn g() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/wrong-version-syntax.rs b/tests/ui/check-cfg/wrong-version-syntax.rs
new file mode 100644
index 00000000000..221ecf4cae8
--- /dev/null
+++ b/tests/ui/check-cfg/wrong-version-syntax.rs
@@ -0,0 +1,14 @@
+// Check warning for wrong `cfg(version("1.27"))` syntax
+//
+//@ check-pass
+//@ no-auto-check-cfg
+//@ compile-flags: --check-cfg=cfg()
+//@ run-rustfix
+
+#![feature(cfg_version)]
+
+#[cfg(not(version = "1.48.0"))]
+//~^ WARNING unexpected `cfg` condition name: `version`
+pub fn g() {}
+
+pub fn main() {}
diff --git a/tests/ui/check-cfg/wrong-version-syntax.stderr b/tests/ui/check-cfg/wrong-version-syntax.stderr
new file mode 100644
index 00000000000..97157a0c02b
--- /dev/null
+++ b/tests/ui/check-cfg/wrong-version-syntax.stderr
@@ -0,0 +1,17 @@
+warning: unexpected `cfg` condition name: `version`
+  --> $DIR/wrong-version-syntax.rs:10:11
+   |
+LL | #[cfg(not(version = "1.48.0"))]
+   |           ^^^^^^^^^^^^^^^^^^
+   |
+   = help: to expect this configuration use `--check-cfg=cfg(version, values("1.48.0"))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+help: there is a similar config predicate: `version("..")`
+   |
+LL - #[cfg(not(version = "1.48.0"))]
+LL + #[cfg(not(version("1.48.0")))]
+   |
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs
new file mode 100644
index 00000000000..f45b7c3268b
--- /dev/null
+++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs
@@ -0,0 +1,24 @@
+#![feature(generic_arg_infer, associated_const_equality, generic_const_items)]
+#![expect(incomplete_features)]
+
+// Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even
+// though it contained inference variables, which would cause ICEs.
+
+trait Foo {
+    const ASSOC<const N: u32>: u32;
+}
+
+impl Foo for () {
+    const ASSOC<const N: u32>: u32 = N;
+}
+
+fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
+
+fn main() {
+    bar::<_, ()>();
+    //~^ ERROR: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
+
+    // FIXME(mgca):
+    // FIXME(associated_const_equality):
+    // This ought to start compiling once const items are aliases rather than bodies
+}
diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr
new file mode 100644
index 00000000000..00741c901e4
--- /dev/null
+++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.stderr
@@ -0,0 +1,17 @@
+error[E0271]: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
+  --> $DIR/equality_bound_with_infer.rs:18:14
+   |
+LL |     bar::<_, ()>();
+   |              ^^ expected `10`, found `<() as Foo>::ASSOC::<_>`
+   |
+   = note: expected constant `10`
+              found constant `<() as Foo>::ASSOC::<_>`
+note: required by a bound in `bar`
+  --> $DIR/equality_bound_with_infer.rs:15:29
+   |
+LL | fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
+   |                             ^^^^^^^^^^^^^ required by this bound in `bar`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs
new file mode 100644
index 00000000000..99318ef7598
--- /dev/null
+++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs
@@ -0,0 +1,26 @@
+// regression test for #137813 where we would assume all constants in the type system
+// cannot contain inference variables, even though associated const equality syntax
+// was still lowered without the feature gate enabled.
+
+trait AssocConst {
+    const A: u8;
+}
+
+impl<T> AssocConst for (T,) {
+    const A: u8 = 0;
+}
+
+trait Trait {}
+
+impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
+//~^ ERROR associated const equality is incomplete
+//~| ERROR the type parameter `U` is not constrained by the impl trait
+
+fn foo()
+where
+    (): Trait,
+    //~^ ERROR type mismatch resolving
+{
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr
new file mode 100644
index 00000000000..e6799ec5c3a
--- /dev/null
+++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr
@@ -0,0 +1,39 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/unconstrained_impl_param.rs:15:45
+   |
+LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
+   |                                             ^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained_impl_param.rs:15:6
+   |
+LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
+   |      ^ unconstrained type parameter
+
+error[E0271]: type mismatch resolving `<(_,) as AssocConst>::A == 0`
+  --> $DIR/unconstrained_impl_param.rs:21:5
+   |
+LL |     (): Trait,
+   |     ^^^^^^^^^ expected `0`, found `<(_,) as AssocConst>::A`
+   |
+   = note: expected constant `0`
+              found constant `<(_,) as AssocConst>::A`
+note: required for `()` to implement `Trait`
+  --> $DIR/unconstrained_impl_param.rs:15:9
+   |
+LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
+   |         ^^^^^     ^^                        --------- unsatisfied trait bound introduced here
+   = help: see issue #48214
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+LL + #![feature(trivial_bounds)]
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0207, E0271, E0658.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/crashes/auxiliary/aux133199.rs b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs
index 40765d92fbf..a8bda14f4bd 100644
--- a/tests/crashes/auxiliary/aux133199.rs
+++ b/tests/ui/const-generics/generic_const_exprs/auxiliary/cross-crate-2.rs
@@ -1,9 +1,9 @@
 #![allow(incomplete_features)]
 #![feature(generic_const_exprs)]
 
-pub struct FixedBitSet<const N: usize>;
+pub struct Foo<const N: usize>;
 
-impl<const N: usize> FixedBitSet<N>
+impl<const N: usize> Foo<N>
 where
     [u8; N.div_ceil(8)]: Sized,
 {
diff --git a/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs
new file mode 100644
index 00000000000..77998c7ec0a
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/cross-crate-2.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+//@ aux-build: cross-crate-2.rs
+
+extern crate cross_crate_2;
+
+use cross_crate_2::Foo;
+
+fn main() {
+    Foo::<7>::new();
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
index f454ff4e6c0..6b095f3818a 100644
--- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.full.stderr
@@ -1,5 +1,5 @@
 error: generic parameters may not be used in const operations
-  --> $DIR/dependence_lint.rs:14:32
+  --> $DIR/dependence_lint.rs:15:32
    |
 LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    |                                ^ cannot perform const operation using `T`
@@ -8,7 +8,7 @@ LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/dependence_lint.rs:21:37
+  --> $DIR/dependence_lint.rs:22:37
    |
 LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
    |                                     ^ cannot perform const operation using `T`
@@ -27,7 +27,7 @@ LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_
    = note: `#[warn(const_evaluatable_unchecked)]` on by default
 
 warning: cannot use constants which depend on generic parameters in types
-  --> $DIR/dependence_lint.rs:17:9
+  --> $DIR/dependence_lint.rs:18:9
    |
 LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
index f6119c17bf4..12ac980c975 100644
--- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr
@@ -9,8 +9,19 @@ help: try adding a `where` bound
 LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
    |             ++++++++++++++++++++++++++++++++
 
+error: unconstrained generic constant
+  --> $DIR/dependence_lint.rs:10:5
+   |
+LL |     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try adding a `where` bound
+   |
+LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
+   |             ++++++++++++++++++++++++++++++++
+
 error: overly complex generic constant
-  --> $DIR/dependence_lint.rs:17:9
+  --> $DIR/dependence_lint.rs:18:9
    |
 LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
@@ -18,7 +29,7 @@ LL |     [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error w
    = help: consider moving this anonymous constant into a `const` function
 
 error: unconstrained generic constant
-  --> $DIR/dependence_lint.rs:14:12
+  --> $DIR/dependence_lint.rs:15:12
    |
 LL |     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,12 +40,12 @@ LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
    |             ++++++++++++++++++++++++++++++++
 
 error: overly complex generic constant
-  --> $DIR/dependence_lint.rs:21:17
+  --> $DIR/dependence_lint.rs:22:17
    |
 LL |     let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs
index 107466cd1d9..6b3c8f84be3 100644
--- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs
+++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.rs
@@ -9,7 +9,8 @@ use std::mem::size_of;
 fn foo<T>() {
     [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
     //[gce]~^ ERROR unconstrained
-    //[full]~^^ WARNING cannot use constants
+    //[gce]~| ERROR unconstrained generic constant
+    //[full]~^^^ WARNING cannot use constants
     //[full]~| WARNING this was previously accepted
     let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
     //[full]~^ ERROR generic parameters may not be used
diff --git a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr
index ac80463480d..52917df0da1 100644
--- a/tests/ui/const-generics/generic_const_exprs/different-fn.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/different-fn.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/different-fn.rs:10:5
    |
 LL |     [0; size_of::<Foo<T>>()]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `0`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
    |
    = note: expected constant `size_of::<T>()`
-              found constant `0`
+              found constant `size_of::<Foo<T>>()`
 
 error: unconstrained generic constant
   --> $DIR/different-fn.rs:10:9
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
index 9ab715d01f7..da9a75b50ef 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs
@@ -15,7 +15,7 @@ impl Foo for () {
 }
 
 fn use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` is not dyn compatible
-    v.test(); //~ERROR the trait `Foo` is not dyn compatible
+    v.test();
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
index 8bc6ef093d0..120ee435e25 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr
@@ -17,25 +17,6 @@ LL |     fn test(&self) -> [u8; bar::<Self>()];
    = help: consider moving `test` to another trait
    = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/dyn-compatibility-err-ret.rs:18:5
-   |
-LL |     v.test();
-   |     ^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-compatibility-err-ret.rs:8:8
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn test(&self) -> [u8; bar::<Self>()];
-   |        ^^^^           ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
-   |        |
-   |        ...because method `test` references the `Self` type in its `where` clause
-   = help: consider moving `test` to another trait
-   = help: only type `()` implements `Foo`; consider using it directly instead.
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
index a7b771cd4f8..8b735188f32 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs
@@ -15,7 +15,6 @@ impl Foo for () {
 fn use_dyn(v: &dyn Foo) {
     //~^ ERROR the trait `Foo` is not dyn compatible
     v.test();
-    //~^ ERROR the trait `Foo` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
index f5eaaa37916..c2ad4d14988 100644
--- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr
@@ -15,23 +15,6 @@ LL |     fn test(&self) where [u8; bar::<Self>()]: Sized;
    = help: consider moving `test` to another trait
    = help: only type `()` implements `Foo`; consider using it directly instead.
 
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/dyn-compatibility-err-where-bounds.rs:17:5
-   |
-LL |     v.test();
-   |     ^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn test(&self) where [u8; bar::<Self>()]: Sized;
-   |        ^^^^ ...because method `test` references the `Self` type in its `where` clause
-   = help: consider moving `test` to another trait
-   = help: only type `()` implements `Foo`; consider using it directly instead.
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs
new file mode 100644
index 00000000000..83b73350f83
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/serializing_error_guaranteed.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+
+// regression test for #136894.
+// I (BoxyUwU) don't know what the underlying cause was here
+
+#![feature(generic_const_exprs)]
+#![crate_type = "lib"]
+#![allow(incomplete_features, dead_code)]
+
+struct X<T>([(); f::<T>()])
+where
+    [(); f::<T>()]:;
+
+const fn f<T>() -> usize {
+    panic!()
+}
diff --git a/tests/ui/const-generics/issues/issue-71202.rs b/tests/ui/const-generics/issues/issue-71202.rs
index 0f955414d84..8ff49b55e6f 100644
--- a/tests/ui/const-generics/issues/issue-71202.rs
+++ b/tests/ui/const-generics/issues/issue-71202.rs
@@ -25,7 +25,9 @@ impl<T: Copy> DataHolder<T> {
         }
 
         <IsCopy<T>>::VALUE
-    } as usize] = []; //~ ERROR unconstrained generic constant
+    } as usize] = [];
+    //~^ ERROR unconstrained generic constant
+    //~^^ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/issues/issue-71202.stderr b/tests/ui/const-generics/issues/issue-71202.stderr
index cc3603d1145..b7c3db494a5 100644
--- a/tests/ui/const-generics/issues/issue-71202.stderr
+++ b/tests/ui/const-generics/issues/issue-71202.stderr
@@ -59,5 +59,49 @@ LL +         <IsCopy<T>>::VALUE
 LL ~     } as usize]: = [];
    |
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-71202.rs:28:19
+   |
+LL |     } as usize] = [];
+   |                   ^^ expected `1 - {
+        trait NotCopy {
+            const VALUE: bool = false;
+        }
+
+        impl<__Type: ?Sized> NotCopy for __Type {}
+
+        struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
+
+        impl<__Type> IsCopy<__Type>
+        where
+            __Type: Sized + Copy,
+        {
+            const VALUE: bool = true;
+        }
+
+        <IsCopy<T>>::VALUE
+    } as usize`, found `0`
+   |
+   = note: expected constant `1 - {
+                   trait NotCopy {
+                       const VALUE: bool = false;
+                   }
+           
+                   impl<__Type: ?Sized> NotCopy for __Type {}
+           
+                   struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
+           
+                   impl<__Type> IsCopy<__Type>
+                   where
+                       __Type: Sized + Copy,
+                   {
+                       const VALUE: bool = true;
+                   }
+           
+                   <IsCopy<T>>::VALUE
+               } as usize`
+              found constant `0`
+
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/issues/issue-83765.rs b/tests/ui/const-generics/issues/issue-83765.rs
index 0959f771c22..f31c61408e9 100644
--- a/tests/ui/const-generics/issues/issue-83765.rs
+++ b/tests/ui/const-generics/issues/issue-83765.rs
@@ -3,10 +3,6 @@
 
 trait TensorDimension {
     const DIM: usize;
-    //~^ ERROR cycle detected when resolving instance
-    //~| ERROR cycle detected when resolving instance
-    // FIXME Given the current state of the compiler its expected that we cycle here,
-    // but the cycle is still wrong.
     const ISSCALAR: bool = Self::DIM == 0;
     fn is_scalar(&self) -> bool {
         Self::ISSCALAR
@@ -49,6 +45,7 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T
 
 impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> {
     fn size(&self) -> [usize; DIM] {
+        //~^ ERROR: method not compatible with trait
         self.size
     }
 }
@@ -56,12 +53,17 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T
 impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> {
     type Element = T::Element;
     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
+        //~^ ERROR: method not compatible with trait
         assert!(DIM >= T::DIM);
         if !self.inbounds(index) {
+            //~^ ERROR: unconstrained generic constant
+            //~| ERROR: mismatched types
             return None;
         }
         let size = self.size();
+        //~^ ERROR: unconstrained generic constant
         let newindex: [usize; T::DIM] = Default::default();
+        //~^ ERROR: the trait bound
         self.reference.bget(newindex)
     }
 }
@@ -82,6 +84,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSi
     fn size(&self) -> [usize; DIM] {
         //~^ ERROR: method not compatible with trait
         self.reference.size()
+        //~^ ERROR: unconstrained generic constant
+        //~| ERROR: mismatched types
     }
 }
 
@@ -92,6 +96,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcas
     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
         //~^ ERROR: method not compatible with trait
         self.reference.bget(index).map(&self.closure)
+        //~^ ERROR: unconstrained generic constant
+        //~| ERROR: mismatched types
     }
 }
 
@@ -100,12 +106,14 @@ impl<T> TensorDimension for Vec<T> {
 }
 impl<T> TensorSize for Vec<T> {
     fn size(&self) -> [usize; 1] {
+        //~^ ERROR: method not compatible with trait
         [self.len()]
     }
 }
 impl<T: Clone> Broadcastable for Vec<T> {
     type Element = T;
     fn bget(&self, index: [usize; 1]) -> Option<T> {
+        //~^ ERROR: method not compatible with trait
         self.get(index[0]).cloned()
     }
 }
diff --git a/tests/ui/const-generics/issues/issue-83765.stderr b/tests/ui/const-generics/issues/issue-83765.stderr
index 6b62012c14f..5a06ee7ddbc 100644
--- a/tests/ui/const-generics/issues/issue-83765.stderr
+++ b/tests/ui/const-generics/issues/issue-83765.stderr
@@ -1,43 +1,23 @@
-error[E0391]: cycle detected when resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`
-  --> $DIR/issue-83765.rs:5:5
-   |
-LL |     const DIM: usize;
-   |     ^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>`...
-  --> $DIR/issue-83765.rs:4:1
-   |
-LL | trait TensorDimension {
-   | ^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
-note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:50:1: 50:94>::size` is compatible with trait definition
-  --> $DIR/issue-83765.rs:51:5
+error[E0308]: method not compatible with trait
+  --> $DIR/issue-83765.rs:47:5
    |
 LL |     fn size(&self) -> [usize; DIM] {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error[E0391]: cycle detected when resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`
-  --> $DIR/issue-83765.rs:5:5
-   |
-LL |     const DIM: usize;
-   |     ^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>`...
-  --> $DIR/issue-83765.rs:4:1
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
    |
-LL | trait TensorDimension {
-   | ^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
-note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:56:1: 56:97>::bget` is compatible with trait definition
-  --> $DIR/issue-83765.rs:58:5
+   = note: expected constant `Self::DIM`
+              found constant `DIM`
+
+error[E0308]: method not compatible with trait
+  --> $DIR/issue-83765.rs:55:5
    |
 LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
+   |
+   = note: expected constant `Self::DIM`
+              found constant `DIM`
 
 error[E0308]: method not compatible with trait
-  --> $DIR/issue-83765.rs:82:5
+  --> $DIR/issue-83765.rs:84:5
    |
 LL |     fn size(&self) -> [usize; DIM] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@@ -46,7 +26,7 @@ LL |     fn size(&self) -> [usize; DIM] {
               found constant `DIM`
 
 error[E0308]: method not compatible with trait
-  --> $DIR/issue-83765.rs:92:5
+  --> $DIR/issue-83765.rs:96:5
    |
 LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@@ -54,7 +34,127 @@ LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
    = note: expected constant `Self::DIM`
               found constant `DIM`
 
-error: aborting due to 4 previous errors
+error[E0308]: method not compatible with trait
+  --> $DIR/issue-83765.rs:108:5
+   |
+LL |     fn size(&self) -> [usize; 1] {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1`
+   |
+   = note: expected constant `Self::DIM`
+              found constant `1`
+
+error[E0308]: method not compatible with trait
+  --> $DIR/issue-83765.rs:115:5
+   |
+LL |     fn bget(&self, index: [usize; 1]) -> Option<T> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1`
+   |
+   = note: expected constant `Self::DIM`
+              found constant `1`
+
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:58:13
+   |
+LL |         if !self.inbounds(index) {
+   |             ^^^^
+   |
+note: required by a bound in `TensorSize::inbounds`
+  --> $DIR/issue-83765.rs:14:39
+   |
+LL |     fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
+   |                                       ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
+help: try adding a `where` bound
+   |
+LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
+   |                                                                  ++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-83765.rs:58:27
+   |
+LL |         if !self.inbounds(index) {
+   |                           ^^^^^ expected `Self::DIM`, found `DIM`
+   |
+   = note: expected constant `Self::DIM`
+              found constant `DIM`
+
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:63:25
+   |
+LL |         let size = self.size();
+   |                         ^^^^
+   |
+note: required by a bound in `TensorSize::size`
+  --> $DIR/issue-83765.rs:13:31
+   |
+LL |     fn size(&self) -> [usize; Self::DIM];
+   |                               ^^^^^^^^^ required by this bound in `TensorSize::size`
+help: try adding a `where` bound
+   |
+LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
+   |                                                                  ++++++++++++++++++++++
+
+error[E0277]: the trait bound `[usize; T::DIM]: Default` is not satisfied
+  --> $DIR/issue-83765.rs:65:41
+   |
+LL |         let newindex: [usize; T::DIM] = Default::default();
+   |                                         ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; T::DIM]`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> where [usize; T::DIM]: Default {
+   |                                                                                                  ++++++++++++++++++++++++++++++
+
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:86:24
+   |
+LL |         self.reference.size()
+   |                        ^^^^
+   |
+note: required by a bound in `TensorSize::size`
+  --> $DIR/issue-83765.rs:13:31
+   |
+LL |     fn size(&self) -> [usize; Self::DIM];
+   |                               ^^^^^^^^^ required by this bound in `TensorSize::size`
+help: try adding a `where` bound
+   |
+LL |     fn size(&self) -> [usize; DIM] where [(); Self::DIM]: {
+   |                                    ++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-83765.rs:86:9
+   |
+LL |         self.reference.size()
+   |         ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
+   |
+   = note: expected constant `DIM`
+              found constant `Self::DIM`
+
+error: unconstrained generic constant
+  --> $DIR/issue-83765.rs:98:9
+   |
+LL |         self.reference.bget(index).map(&self.closure)
+   |         ^^^^^^^^^^^^^^
+   |
+note: required by a bound in `Broadcastable::bget`
+  --> $DIR/issue-83765.rs:21:35
+   |
+LL |     fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
+   |                                   ^^^^^^^^^ required by this bound in `Broadcastable::bget`
+help: try adding a `where` bound
+   |
+LL |     fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
+   |                                                                  ++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-83765.rs:98:29
+   |
+LL |         self.reference.bget(index).map(&self.closure)
+   |                             ^^^^^ expected `Self::DIM`, found `DIM`
+   |
+   = note: expected constant `Self::DIM`
+              found constant `DIM`
+
+error: aborting due to 14 previous errors
 
-Some errors have detailed explanations: E0308, E0391.
-For more information about an error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/const-generics/mgca/projection-error.rs b/tests/ui/const-generics/mgca/projection-error.rs
new file mode 100644
index 00000000000..d1c4fa8a492
--- /dev/null
+++ b/tests/ui/const-generics/mgca/projection-error.rs
@@ -0,0 +1,17 @@
+#![feature(min_generic_const_args)]
+#![expect(incomplete_features)]
+
+// Regression test for #140642. Test that normalizing const aliases
+// containing erroneous types normalizes to a const error instead of
+// a type error.
+
+
+pub trait Tr<A> {
+    const SIZE: usize;
+}
+
+fn mk_array(_x: T) -> [(); <T as Tr<bool>>::SIZE] {}
+//~^ ERROR: cannot find type `T` in this scope
+//~| ERROR: cannot find type `T` in this scope
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/projection-error.stderr b/tests/ui/const-generics/mgca/projection-error.stderr
new file mode 100644
index 00000000000..e6888351da1
--- /dev/null
+++ b/tests/ui/const-generics/mgca/projection-error.stderr
@@ -0,0 +1,39 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/projection-error.rs:13:17
+   |
+LL | pub trait Tr<A> {
+   | --------------- similarly named trait `Tr` defined here
+...
+LL | fn mk_array(_x: T) -> [(); <T as Tr<bool>>::SIZE] {}
+   |                 ^
+   |
+help: a trait with a similar name exists
+   |
+LL | fn mk_array(_x: Tr) -> [(); <T as Tr<bool>>::SIZE] {}
+   |                  +
+help: you might be missing a type parameter
+   |
+LL | fn mk_array<T>(_x: T) -> [(); <T as Tr<bool>>::SIZE] {}
+   |            +++
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/projection-error.rs:13:29
+   |
+LL | pub trait Tr<A> {
+   | --------------- similarly named trait `Tr` defined here
+...
+LL | fn mk_array(_x: T) -> [(); <T as Tr<bool>>::SIZE] {}
+   |                             ^
+   |
+help: a trait with a similar name exists
+   |
+LL | fn mk_array(_x: T) -> [(); <Tr as Tr<bool>>::SIZE] {}
+   |                              +
+help: you might be missing a type parameter
+   |
+LL | fn mk_array<T>(_x: T) -> [(); <T as Tr<bool>>::SIZE] {}
+   |            +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs
index 13a95f9b78f..1383de63109 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.rs
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs
@@ -19,7 +19,7 @@ const MISALIGNED_COPY: () = unsafe {
     y.copy_to_nonoverlapping(&mut z, 1);
     //~^ ERROR evaluation of constant value failed
     //~| NOTE inside `std::ptr::const_ptr
-    //~| NOTE inside `copy_nonoverlapping::<u32>`
+    //~| NOTE inside `std::ptr::copy_nonoverlapping::<u32>`
     //~| NOTE accessing memory with alignment 1, but alignment 4 is required
     // The actual error points into the implementation of `copy_to_nonoverlapping`.
 };
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
index ed5793c84c5..0f3dc33f3a3 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
@@ -18,8 +18,8 @@ LL |     y.copy_to_nonoverlapping(&mut z, 1);
    |
 note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `copy_nonoverlapping::<u32>`
-  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+note: inside `std::ptr::copy_nonoverlapping::<u32>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/raw-pointer-ub.rs:34:16
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index da483d671f9..d0242f28544 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -1,22 +1,8 @@
-#![stable(feature = "dummy", since = "1.0.0")]
-
 // ignore-tidy-linelength
-#![feature(intrinsics, staged_api, rustc_attrs)]
-use std::mem;
-
-#[stable(feature = "dummy", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[rustc_intrinsic]
-const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
-    unimplemented!()
-}
+#![feature(core_intrinsics)]
 
-#[stable(feature = "dummy", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[rustc_intrinsic]
-const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
-    unimplemented!()
-}
+use std::mem;
+use std::intrinsics::{copy, copy_nonoverlapping};
 
 const COPY_ZERO: () = unsafe {
     // Since we are not copying anything, this should be allowed.
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index 13321b5703a..8d586428e56 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:34:5
+  --> $DIR/copy-intrinsic.rs:20:5
    |
 LL |     copy_nonoverlapping(0x100 as *const i32, dangle, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:43:5
+  --> $DIR/copy-intrinsic.rs:29:5
    |
 LL |     copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:50:5
+  --> $DIR/copy-intrinsic.rs:36:5
    |
 LL |     copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:56:5
+  --> $DIR/copy-intrinsic.rs:42:5
    |
 LL |     copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr
index 88b3e37bb84..7c07710332b 100644
--- a/tests/ui/consts/missing_span_in_backtrace.stderr
+++ b/tests/ui/consts/missing_span_in_backtrace.stderr
@@ -14,8 +14,8 @@ note: inside `swap_nonoverlapping::compiletime::<MaybeUninit<u8>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `std::ptr::swap_nonoverlapping_const::<MaybeUninit<u8>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `copy_nonoverlapping::<MaybeUninit<u8>>`
-  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+note: inside `std::ptr::copy_nonoverlapping::<MaybeUninit<u8>>`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
    = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
index b76b550fcb2..a0e497fa045 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
@@ -3,7 +3,7 @@
 //@ reference: attributes.diagnostic.on_unimplemented.syntax
 //@ reference: attributes.diagnostic.on_unimplemented.invalid-formats
 #[diagnostic::on_unimplemented(
-    on(_Self = "&str"),
+    on(Self = "&str"),
     //~^WARN malformed `on_unimplemented` attribute
     //~|WARN malformed `on_unimplemented` attribute
     message = "trait has `{Self}` and `{T}` as params",
@@ -41,7 +41,7 @@ impl Bar for i32 {}
     //~|WARN there is no parameter `integral` on trait `Baz`
     //~|WARN there is no parameter `integer` on trait `Baz`
     //~|WARN there is no parameter `integer` on trait `Baz`
-    label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+    label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
     //~^WARN there is no parameter `float` on trait `Baz`
     //~|WARN there is no parameter `float` on trait `Baz`
     //~|WARN there is no parameter `_Self` on trait `Baz`
@@ -52,6 +52,8 @@ impl Bar for i32 {}
     //~|WARN there is no parameter `Trait` on trait `Baz`
     //~|WARN there is no parameter `ItemContext` on trait `Baz`
     //~|WARN there is no parameter `ItemContext` on trait `Baz`
+    //~|WARN there is no parameter `This` on trait `Baz`
+    //~|WARN there is no parameter `This` on trait `Baz`
 )]
 trait Baz {}
 
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
index 88816a98dcf..8dace7d9052 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
@@ -9,8 +9,8 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5
    |
-LL |     on(_Self = "&str"),
-   |     ^^^^^^^^^^^^^^^^^^ invalid option found here
+LL |     on(Self = "&str"),
+   |     ^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
 
@@ -81,7 +81,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
 warning: there is no parameter `float` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |               ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -89,7 +89,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `_Self` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                      ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -97,7 +97,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `crate_local` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                             ^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -105,7 +105,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `Trait` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                          ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -113,16 +113,24 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `ItemContext` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                                 ^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
 
+warning: there is no parameter `This` on trait `Baz`
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:62
+   |
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
+   |                                                              ^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:6:5
    |
-LL |     on(_Self = "&str"),
-   |     ^^^^^^^^^^^^^^^^^^ invalid option found here
+LL |     on(Self = "&str"),
+   |     ^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -146,7 +154,7 @@ LL |     append_const_msg
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: trait has `()` and `i32` as params
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15
    |
 LL |     takes_foo(());
    |     --------- ^^ trait has `()` and `i32` as params
@@ -161,7 +169,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo<T> {}
    | ^^^^^^^^^^^^
 note: required by a bound in `takes_foo`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22
    |
 LL | fn takes_foo(_: impl Foo<i32>) {}
    |                      ^^^^^^^^ required by this bound in `takes_foo`
@@ -176,7 +184,7 @@ LL | #[diagnostic::on_unimplemented = "Message"]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15
    |
 LL |     takes_bar(());
    |     --------- ^^ the trait `Bar` is not implemented for `()`
@@ -185,7 +193,7 @@ LL |     takes_bar(());
    |
    = help: the trait `Bar` is implemented for `i32`
 note: required by a bound in `takes_bar`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:22
    |
 LL | fn takes_bar(_: impl Bar) {}
    |                      ^^^ required by this bound in `takes_bar`
@@ -238,7 +246,7 @@ LL |     message = "{from_desugaring}{direct}{cause}{integral}{integer}",
 warning: there is no parameter `float` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |               ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -247,7 +255,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `_Self` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                      ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -256,7 +264,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `crate_local` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                             ^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -265,7 +273,7 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `Trait` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                          ^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
@@ -274,32 +282,41 @@ LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
 warning: there is no parameter `ItemContext` on trait `Baz`
   --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49
    |
-LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
    |                                                 ^^^^^^^^^^^
    |
    = help: expect either a generic argument name or `{Self}` as format argument
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+warning: there is no parameter `This` on trait `Baz`
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:62
+   |
+LL |     label = "{float}{_Self}{crate_local}{Trait}{ItemContext}{This}"
+   |                                                              ^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer}
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:67:15
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:69:15
    |
 LL |     takes_baz(());
-   |     --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}
+   |     --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext}{This}
    |     |
    |     required by a bound introduced by this call
    |
    = help: the trait `Baz` is not implemented for `()`
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:1
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:1
    |
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `takes_baz`
-  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:60:22
+  --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:62:22
    |
 LL | fn takes_baz(_: impl Baz) {}
    |                      ^^^ required by this bound in `takes_baz`
 
-error: aborting due to 3 previous errors; 29 warnings emitted
+error: aborting due to 3 previous errors; 31 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
index 8328c10d2a0..08eb5707e90 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
@@ -14,11 +14,15 @@ struct Bar {}
 //~|WARN malformed `on_unimplemented` attribute
 trait Baz {}
 
-#[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
+#[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))]
 //~^WARN malformed `on_unimplemented` attribute
 //~|WARN malformed `on_unimplemented` attribute
 trait Boom {}
 
+#[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
+//~^WARN malformed `on_unimplemented` attribute
+trait _Self {}
+
 #[diagnostic::on_unimplemented = "boom"]
 //~^WARN malformed `on_unimplemented` attribute
 trait Doom {}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index 4dd8c1afca0..80790dc3f79 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -25,13 +25,21 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
+LL | #[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))]
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
+   |
+   = help: only `message`, `note` and `label` are allowed as options
+
+warning: malformed `on_unimplemented` attribute
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:50
+   |
 LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:32
    |
 LL | #[diagnostic::on_unimplemented = "boom"]
    |                                ^^^^^^^^ invalid option found here
@@ -39,7 +47,7 @@ LL | #[diagnostic::on_unimplemented = "boom"]
    = help: only `message`, `note` and `label` are allowed as options
 
 warning: missing options for `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:30:1
    |
 LL | #[diagnostic::on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +55,7 @@ LL | #[diagnostic::on_unimplemented]
    = help: at least one of the `message`, `note` and `label` options are expected
 
 warning: there is no parameter `DoesNotExist` on trait `Test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:44
    |
 LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    |                                            ^^^^^^^^^^^^
@@ -64,7 +72,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:14
    |
 LL |     take_foo(1_i32);
    |     -------- ^^^^^ the trait `Foo` is not implemented for `i32`
@@ -77,7 +85,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Foo {}
    | ^^^^^^^^^
 note: required by a bound in `take_foo`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:21
    |
 LL | fn take_foo(_: impl Foo) {}
    |                     ^^^ required by this bound in `take_foo`
@@ -92,7 +100,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:14
    |
 LL |     take_baz(1_i32);
    |     -------- ^^^^^ the trait `Baz` is not implemented for `i32`
@@ -105,7 +113,7 @@ help: this trait has no implementations, consider adding one
 LL | trait Baz {}
    | ^^^^^^^^^
 note: required by a bound in `take_baz`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:21
    |
 LL | fn take_baz(_: impl Baz) {}
    |                     ^^^ required by this bound in `take_baz`
@@ -113,14 +121,14 @@ LL | fn take_baz(_: impl Baz) {}
 warning: malformed `on_unimplemented` attribute
   --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
    |
-LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
+LL | #[diagnostic::on_unimplemented(message = "Boom", on(Self = "i32", message = "whatever"))]
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
    |
    = help: only `message`, `note` and `label` are allowed as options
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Boom
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15
    |
 LL |     take_boom(1_i32);
    |     --------- ^^^^^ the trait `Boom` is not implemented for `i32`
@@ -133,13 +141,13 @@ help: this trait has no implementations, consider adding one
 LL | trait Boom {}
    | ^^^^^^^^^^
 note: required by a bound in `take_boom`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:42:22
    |
 LL | fn take_boom(_: impl Boom) {}
    |                      ^^^^ required by this bound in `take_boom`
 
 warning: missing options for `on_unimplemented` attribute
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:30:1
    |
 LL | #[diagnostic::on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +156,7 @@ LL | #[diagnostic::on_unimplemented]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `i32: Whatever` is not satisfied
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:53:19
    |
 LL |     take_whatever(1_i32);
    |     ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
@@ -156,18 +164,18 @@ LL |     take_whatever(1_i32);
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:1
    |
 LL | trait Whatever {}
    | ^^^^^^^^^^^^^^
 note: required by a bound in `take_whatever`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:26
    |
 LL | fn take_whatever(_: impl Whatever) {}
    |                          ^^^^^^^^ required by this bound in `take_whatever`
 
 warning: there is no parameter `DoesNotExist` on trait `Test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:44
    |
 LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    |                                            ^^^^^^^^^^^^
@@ -176,7 +184,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: {DoesNotExist}
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:55:15
    |
 LL |     take_test(());
    |     --------- ^^ the trait `Test` is not implemented for `()`
@@ -184,16 +192,16 @@ LL |     take_test(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:1
    |
 LL | trait Test {}
    | ^^^^^^^^^^
 note: required by a bound in `take_test`
-  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22
+  --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:44:22
    |
 LL | fn take_test(_: impl Test) {}
    |                      ^^^^ required by this bound in `take_test`
 
-error: aborting due to 5 previous errors; 12 warnings emitted
+error: aborting due to 5 previous errors; 13 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
index 71158cb8062..6c8d2d3fa9c 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.fixed
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -24,6 +24,7 @@
 //@ [e2024] edition: 2024
 //@ run-pass
 
+#![feature(if_let_guard)]
 #![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
@@ -344,6 +345,25 @@ fn t_if_let_chains_then() {
     e.assert(9);
 }
 
+#[rustfmt::skip]
+fn t_guard_if_let_chains_then() {
+    let e = Events::new();
+    _ = match () {
+        () if e.ok(1).is_ok()
+            && let true = e.ok(9).is_ok()
+            && let Ok(_v) = e.ok(8)
+            && let Ok(_) = e.ok(7)
+            && let Ok(_) = e.ok(6).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(5)
+            && let Ok(_) = e.ok(4).as_ref() => {
+                e.mark(3);
+            }
+        _ => {}
+    };
+    e.assert(9);
+}
+
 #[cfg(e2021)]
 #[rustfmt::skip]
 fn t_if_let_nested_else() {
@@ -484,6 +504,25 @@ fn t_if_let_chains_then_else() {
     e.assert(9);
 }
 
+#[rustfmt::skip]
+fn t_guard_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = match () {
+       () if e.ok(1).is_ok()
+            && let true = e.ok(8).is_ok()
+            && let Ok(_v) = e.ok(7)
+            && let Ok(_) = e.ok(6)
+            && let Ok(_) = e.ok(5).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(4)
+            && let Ok(_) = e.err(3) => {}
+        _ => {
+            e.mark(9);
+        }
+    };
+    e.assert(9);
+}
+
 fn main() {
     t_bindings();
     t_tuples();
@@ -502,10 +541,12 @@ fn main() {
     t_if_let_nested_then();
     t_let_else_chained_then();
     t_if_let_chains_then();
+    t_guard_if_let_chains_then();
     t_if_let_nested_else();
     t_if_let_nested_then_else();
     t_let_else_chained_then_else();
     t_if_let_chains_then_else();
+    t_guard_if_let_chains_then_else();
 }
 
 // # Test scaffolding
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
index 0717a8c1b9b..8b93376cc0d 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.stderr
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -1,5 +1,5 @@
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:76:9
+  --> $DIR/drop-order-comparisons.rs:77:9
    |
 LL |       _ = ({
    |  _________-
@@ -29,35 +29,35 @@ LL | |     }, e.mark(3), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#3` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `_v` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
-  --> $DIR/drop-order-comparisons.rs:28:25
+  --> $DIR/drop-order-comparisons.rs:29:25
    |
 LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))]
    |                         ^^^^^^^^^^^^^^^^^^^^^^^
    = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]`
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:100:45
+  --> $DIR/drop-order-comparisons.rs:101:45
    |
 LL |       _ = ({
    |  _________-
@@ -77,19 +77,19 @@ LL | |     }, e.mark(1), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:100:19
+  --> $DIR/drop-order-comparisons.rs:101:19
    |
 LL |       _ = ({
    |  _________-
@@ -109,19 +109,19 @@ LL | |     }, e.mark(1), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:221:24
+  --> $DIR/drop-order-comparisons.rs:222:24
    |
 LL |       _ = ({
    |  _________-
@@ -141,19 +141,19 @@ LL | |     }, e.mark(2), e.ok(3));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:247:24
+  --> $DIR/drop-order-comparisons.rs:248:24
    |
 LL |       _ = ({
    |  _________-
@@ -173,19 +173,19 @@ LL | |     }, e.mark(2), e.ok(3));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:123:13
+  --> $DIR/drop-order-comparisons.rs:124:13
    |
 LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
    |             ^^^^^^^^^^^^-------^^^^^^^^^
@@ -195,12 +195,12 @@ LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:127:5
+  --> $DIR/drop-order-comparisons.rs:128:5
    |
 LL |     }, e.mark(2), e.ok(3));
    |     ^
@@ -215,7 +215,7 @@ LL ~     } _ => {}}, e.mark(2), e.ok(3));
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:145:13
+  --> $DIR/drop-order-comparisons.rs:146:13
    |
 LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    |             ^^^^^^^^^^^^--------^^^^^^^^^
@@ -225,12 +225,12 @@ LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:145:44
+  --> $DIR/drop-order-comparisons.rs:146:44
    |
 LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    |                                            ^
@@ -244,7 +244,7 @@ LL ~     }}, e.mark(2), e.ok(3));
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:247:12
+  --> $DIR/drop-order-comparisons.rs:248:12
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -254,12 +254,12 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:247:43
+  --> $DIR/drop-order-comparisons.rs:248:43
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |                                           ^
@@ -273,7 +273,7 @@ LL ~         }}
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:352:12
+  --> $DIR/drop-order-comparisons.rs:372:12
    |
 LL |         if let true = e.err(9).is_ok() {} else {
    |            ^^^^^^^^^^^--------^^^^^^^^
@@ -283,12 +283,12 @@ LL |         if let true = e.err(9).is_ok() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:352:41
+  --> $DIR/drop-order-comparisons.rs:372:41
    |
 LL |         if let true = e.err(9).is_ok() {} else {
    |                                         ^
@@ -302,7 +302,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:355:12
+  --> $DIR/drop-order-comparisons.rs:375:12
    |
 LL |         if let Ok(_v) = e.err(8) {} else {
    |            ^^^^^^^^^^^^^--------
@@ -312,12 +312,12 @@ LL |         if let Ok(_v) = e.err(8) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:355:35
+  --> $DIR/drop-order-comparisons.rs:375:35
    |
 LL |         if let Ok(_v) = e.err(8) {} else {
    |                                   ^
@@ -331,7 +331,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:358:12
+  --> $DIR/drop-order-comparisons.rs:378:12
    |
 LL |         if let Ok(_) = e.err(7) {} else {
    |            ^^^^^^^^^^^^--------
@@ -341,12 +341,12 @@ LL |         if let Ok(_) = e.err(7) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:358:34
+  --> $DIR/drop-order-comparisons.rs:378:34
    |
 LL |         if let Ok(_) = e.err(7) {} else {
    |                                  ^
@@ -360,7 +360,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:361:12
+  --> $DIR/drop-order-comparisons.rs:381:12
    |
 LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -370,12 +370,12 @@ LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:361:43
+  --> $DIR/drop-order-comparisons.rs:381:43
    |
 LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    |                                           ^
@@ -389,7 +389,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:365:12
+  --> $DIR/drop-order-comparisons.rs:385:12
    |
 LL |         if let Ok(_v) = e.err(5) {} else {
    |            ^^^^^^^^^^^^^--------
@@ -399,12 +399,12 @@ LL |         if let Ok(_v) = e.err(5) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:365:35
+  --> $DIR/drop-order-comparisons.rs:385:35
    |
 LL |         if let Ok(_v) = e.err(5) {} else {
    |                                   ^
@@ -418,7 +418,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:368:12
+  --> $DIR/drop-order-comparisons.rs:388:12
    |
 LL |         if let Ok(_) = e.err(4) {} else {
    |            ^^^^^^^^^^^^--------
@@ -428,12 +428,12 @@ LL |         if let Ok(_) = e.err(4) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:368:34
+  --> $DIR/drop-order-comparisons.rs:388:34
    |
 LL |         if let Ok(_) = e.err(4) {} else {
    |                                  ^
@@ -447,7 +447,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:404:12
+  --> $DIR/drop-order-comparisons.rs:424:12
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -457,12 +457,12 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:571:1
+  --> $DIR/drop-order-comparisons.rs:612:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:404:43
+  --> $DIR/drop-order-comparisons.rs:424:43
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |                                           ^
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
index 0492b3a4db7..9a10a08a3ff 100644
--- a/tests/ui/drop/drop-order-comparisons.rs
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -24,6 +24,7 @@
 //@ [e2024] edition: 2024
 //@ run-pass
 
+#![feature(if_let_guard)]
 #![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
@@ -344,6 +345,25 @@ fn t_if_let_chains_then() {
     e.assert(9);
 }
 
+#[rustfmt::skip]
+fn t_guard_if_let_chains_then() {
+    let e = Events::new();
+    _ = match () {
+        () if e.ok(1).is_ok()
+            && let true = e.ok(9).is_ok()
+            && let Ok(_v) = e.ok(8)
+            && let Ok(_) = e.ok(7)
+            && let Ok(_) = e.ok(6).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(5)
+            && let Ok(_) = e.ok(4).as_ref() => {
+                e.mark(3);
+            }
+        _ => {}
+    };
+    e.assert(9);
+}
+
 #[cfg(e2021)]
 #[rustfmt::skip]
 fn t_if_let_nested_else() {
@@ -484,6 +504,25 @@ fn t_if_let_chains_then_else() {
     e.assert(9);
 }
 
+#[rustfmt::skip]
+fn t_guard_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = match () {
+       () if e.ok(1).is_ok()
+            && let true = e.ok(8).is_ok()
+            && let Ok(_v) = e.ok(7)
+            && let Ok(_) = e.ok(6)
+            && let Ok(_) = e.ok(5).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(4)
+            && let Ok(_) = e.err(3) => {}
+        _ => {
+            e.mark(9);
+        }
+    };
+    e.assert(9);
+}
+
 fn main() {
     t_bindings();
     t_tuples();
@@ -502,10 +541,12 @@ fn main() {
     t_if_let_nested_then();
     t_let_else_chained_then();
     t_if_let_chains_then();
+    t_guard_if_let_chains_then();
     t_if_let_nested_else();
     t_if_let_nested_then_else();
     t_let_else_chained_then_else();
     t_if_let_chains_then_else();
+    t_guard_if_let_chains_then_else();
 }
 
 // # Test scaffolding
diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
index ec32bec7785..ac3c2aadf29 100644
--- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
+++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs
@@ -25,5 +25,4 @@ pub fn foo() {
     let fetcher = fetcher();
     //~^ ERROR the trait `Fetcher` is not dyn compatible
     let _ = fetcher.get();
-    //~^ ERROR the trait `Fetcher` is not dyn compatible
 }
diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
index 1299167159e..867a719e2eb 100644
--- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
+++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr
@@ -34,24 +34,6 @@ LL | pub trait Fetcher: Send + Sync {
 LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
    |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
 
-error[E0038]: the trait `Fetcher` is not dyn compatible
-  --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:27:13
-   |
-LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
-   |                      ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
-...
-LL |     let _ = fetcher.get();
-   |             ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22
-   |
-LL | pub trait Fetcher: Send + Sync {
-   |           ------- this trait is not dyn compatible...
-LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
-   |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/error-codes/E0038.rs b/tests/ui/error-codes/E0038.rs
index a467767c3fa..9757e2ab10c 100644
--- a/tests/ui/error-codes/E0038.rs
+++ b/tests/ui/error-codes/E0038.rs
@@ -5,8 +5,6 @@ trait Trait {
 fn call_foo(x: Box<dyn Trait>) {
     //~^ ERROR E0038
     let y = x.foo();
-    //~^ ERROR E0038
-    //~| ERROR E0277
 }
 
 fn main() {
diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr
index 63a5249a386..e09aefaa0dd 100644
--- a/tests/ui/error-codes/E0038.stderr
+++ b/tests/ui/error-codes/E0038.stderr
@@ -14,33 +14,6 @@ LL |     fn foo(&self) -> Self;
    |                      ^^^^ ...because method `foo` references the `Self` type in its return type
    = help: consider moving `foo` to another trait
 
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/E0038.rs:7:13
-   |
-LL |     let y = x.foo();
-   |             ^^^^^^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/E0038.rs:2:22
-   |
-LL | trait Trait {
-   |       ----- this trait is not dyn compatible...
-LL |     fn foo(&self) -> Self;
-   |                      ^^^^ ...because method `foo` references the `Self` type in its return type
-   = help: consider moving `foo` to another trait
-
-error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
-  --> $DIR/E0038.rs:7:9
-   |
-LL |     let y = x.foo();
-   |         ^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `dyn Trait`
-   = note: all local variables must have a statically known size
-   = help: unsized locals are gated as an unstable feature
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0038, E0277.
-For more information about an error, try `rustc --explain E0038`.
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr
index e985a4c9bf0..fbfdce5689a 100644
--- a/tests/ui/error-codes/E0223.stderr
+++ b/tests/ui/error-codes/E0223.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/E0223.rs:8:14
    |
 LL |     let foo: MyTrait::X;
-   |              ^^^^^^^^^^ help: use fully-qualified syntax: `<MyStruct as MyTrait>::X`
+   |              ^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let foo: MyTrait::X;
+LL +     let foo: <MyStruct as MyTrait>::X;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/extern/extern-empty-string-issue-140884.rs b/tests/ui/extern/extern-empty-string-issue-140884.rs
new file mode 100644
index 00000000000..10291513d34
--- /dev/null
+++ b/tests/ui/extern/extern-empty-string-issue-140884.rs
@@ -0,0 +1,3 @@
+extern "" {} //~ ERROR invalid ABI: found ``
+
+fn main() {}
diff --git a/tests/ui/extern/extern-empty-string-issue-140884.stderr b/tests/ui/extern/extern-empty-string-issue-140884.stderr
new file mode 100644
index 00000000000..accae0c0f7c
--- /dev/null
+++ b/tests/ui/extern/extern-empty-string-issue-140884.stderr
@@ -0,0 +1,15 @@
+error[E0703]: invalid ABI: found ``
+  --> $DIR/extern-empty-string-issue-140884.rs:1:8
+   |
+LL | extern "" {}
+   |        ^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+help: there's a similarly named valid ABI `C`
+   |
+LL | extern "C" {}
+   |         +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
index 278a5451e84..50e5fd1ab7a 100644
--- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
+++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
@@ -7,8 +7,6 @@ trait Foo {
 async fn takes_dyn_trait(x: &dyn Foo) {
     //~^ ERROR the trait `Foo` is not dyn compatible
     x.bar().await;
-    //~^ ERROR the trait `Foo` is not dyn compatible
-    //~| ERROR the trait `Foo` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
index ab8c092a826..fd94b0babdb 100644
--- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
+++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr
@@ -14,38 +14,6 @@ LL |     async fn bar(&self);
    |              ^^^ ...because method `bar` is `async`
    = help: consider moving `bar` to another trait
 
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7
-   |
-LL |     x.bar().await;
-   |       ^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     async fn bar(&self);
-   |              ^^^ ...because method `bar` is `async`
-   = help: consider moving `bar` to another trait
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5
-   |
-LL |     x.bar().await;
-   |     ^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     async fn bar(&self);
-   |              ^^^ ...because method `bar` is `async`
-   = help: consider moving `bar` to another trait
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/fn/coerce-suggestion-infer-region.rs b/tests/ui/fn/coerce-suggestion-infer-region.rs
new file mode 100644
index 00000000000..7edb828c973
--- /dev/null
+++ b/tests/ui/fn/coerce-suggestion-infer-region.rs
@@ -0,0 +1,26 @@
+//! Functions with a mismatch between the expected and found type where the difference is a
+//! reference may trigger analysis for additional help. In this test the expected type will be
+//! &'a Container<&'a u8> and the found type will be Container<&'?0 u8>.
+//!
+//! This test exercises a scenario where the found type being analyzed contains an inference region
+//! variable ('?0). This cannot be used in comparisons because the variable no longer exists by the
+//! time the later analysis is performed.
+//!
+//! This is a regression test of #140823
+
+trait MyFn<P> {}
+
+struct Container<T> {
+    data: T,
+}
+
+struct Desugared {
+    callback: Box<dyn for<'a> MyFn<&'a Container<&'a u8>>>,
+}
+
+fn test(callback: Box<dyn for<'a> MyFn<Container<&'a u8>>>) -> Desugared {
+    Desugared { callback }
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/fn/coerce-suggestion-infer-region.stderr b/tests/ui/fn/coerce-suggestion-infer-region.stderr
new file mode 100644
index 00000000000..9dd0fcf76ce
--- /dev/null
+++ b/tests/ui/fn/coerce-suggestion-infer-region.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-suggestion-infer-region.rs:22:17
+   |
+LL |     Desugared { callback }
+   |                 ^^^^^^^^ expected `Box<dyn MyFn<&Container<&u8>>>`, found `Box<dyn MyFn<Container<&u8>>>`
+   |
+   = note: expected struct `Box<(dyn for<'a> MyFn<&'a Container<&'a u8>> + 'static)>`
+              found struct `Box<(dyn for<'a> MyFn<Container<&'a u8>> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs
index 256cfee4c80..87817111b54 100644
--- a/tests/ui/generic-associated-types/trait-objects.rs
+++ b/tests/ui/generic-associated-types/trait-objects.rs
@@ -8,8 +8,6 @@ trait StreamingIterator {
 fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize {
     //~^ ERROR the trait `StreamingIterator` is not dyn compatible
     x.size_hint().0
-    //~^ ERROR the trait `StreamingIterator` is not dyn compatible
-    //~| ERROR the trait `StreamingIterator` is not dyn compatible
 }
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr
index 7d95718ec87..8c3af6b654a 100644
--- a/tests/ui/generic-associated-types/trait-objects.stderr
+++ b/tests/ui/generic-associated-types/trait-objects.stderr
@@ -14,38 +14,6 @@ LL |     type Item<'a> where Self: 'a;
    |          ^^^^ ...because it contains the generic associated type `Item`
    = help: consider moving `Item` to another trait
 
-error[E0038]: the trait `StreamingIterator` is not dyn compatible
-  --> $DIR/trait-objects.rs:10:7
-   |
-LL |     x.size_hint().0
-   |       ^^^^^^^^^ `StreamingIterator` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/trait-objects.rs:2:10
-   |
-LL | trait StreamingIterator {
-   |       ----------------- this trait is not dyn compatible...
-LL |     type Item<'a> where Self: 'a;
-   |          ^^^^ ...because it contains the generic associated type `Item`
-   = help: consider moving `Item` to another trait
-
-error[E0038]: the trait `StreamingIterator` is not dyn compatible
-  --> $DIR/trait-objects.rs:10:5
-   |
-LL |     x.size_hint().0
-   |     ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/trait-objects.rs:2:10
-   |
-LL | trait StreamingIterator {
-   |       ----------------- this trait is not dyn compatible...
-LL |     type Item<'a> where Self: 'a;
-   |          ^^^^ ...because it contains the generic associated type `Item`
-   = help: consider moving `Item` to another trait
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
index 85b1ba269fc..92203c470bb 100644
--- a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
+++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs
@@ -15,6 +15,4 @@ fn main() {
     //~^ ERROR the trait `Foo` is not dyn compatible
     //~| ERROR the trait `Foo` is not dyn compatible
     let s = i.baz();
-    //~^ ERROR the trait `Foo` is not dyn compatible
-    //~| ERROR the trait `Foo` is not dyn compatible
 }
diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
index 840c27e183f..5c498548aff 100644
--- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
+++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr
@@ -16,40 +16,6 @@ LL |     fn baz(&self) -> impl Debug;
    = help: only type `u32` implements `Foo`; consider using it directly instead.
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/dyn-compatibility.rs:17:15
-   |
-LL |     let s = i.baz();
-   |               ^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-compatibility.rs:4:22
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn baz(&self) -> impl Debug;
-   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
-   = help: consider moving `baz` to another trait
-   = help: only type `u32` implements `Foo`; consider using it directly instead.
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/dyn-compatibility.rs:17:13
-   |
-LL |     let s = i.baz();
-   |             ^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-compatibility.rs:4:22
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn baz(&self) -> impl Debug;
-   |                      ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type
-   = help: consider moving `baz` to another trait
-   = help: only type `u32` implements `Foo`; consider using it directly instead.
-
-error[E0038]: the trait `Foo` is not dyn compatible
   --> $DIR/dyn-compatibility.rs:14:13
    |
 LL |     let i = Box::new(42_u32) as Box<dyn Foo>;
@@ -67,6 +33,6 @@ LL |     fn baz(&self) -> impl Debug;
    = help: only type `u32` implements `Foo`; consider using it directly instead.
    = note: required for the cast from `Box<u32>` to `Box<dyn Foo>`
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/impl-trait/in-trait/not-inferred-generic.rs b/tests/ui/impl-trait/in-trait/not-inferred-generic.rs
new file mode 100644
index 00000000000..3879ea0e626
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.rs
@@ -0,0 +1,13 @@
+trait TypedClient {
+    fn publish_typed<F>(&self) -> impl Sized
+    where
+        F: Clone;
+}
+impl TypedClient for () {
+    fn publish_typed<F>(&self) -> impl Sized {}
+}
+
+fn main() {
+    ().publish_typed();
+    //~^ ERROR type annotations needed [E0283]
+}
diff --git a/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr
new file mode 100644
index 00000000000..07f029d3bb7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/not-inferred-generic.stderr
@@ -0,0 +1,21 @@
+error[E0283]: type annotations needed
+  --> $DIR/not-inferred-generic.rs:11:8
+   |
+LL |     ().publish_typed();
+   |        ^^^^^^^^^^^^^ cannot infer type of the type parameter `F` declared on the method `publish_typed`
+   |
+   = note: cannot satisfy `_: Clone`
+   = note: associated types cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
+note: required by a bound in `TypedClient::publish_typed::{anon_assoc#0}`
+  --> $DIR/not-inferred-generic.rs:4:12
+   |
+LL |         F: Clone;
+   |            ^^^^^ required by this bound in `TypedClient::publish_typed::{anon_assoc#0}`
+help: consider specifying the generic argument
+   |
+LL |     ().publish_typed::<F>();
+   |                     +++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/issues/issue-100075-2.stderr b/tests/ui/impl-trait/issues/issue-100075-2.stderr
index b3b69677507..554c3ea3433 100644
--- a/tests/ui/impl-trait/issues/issue-100075-2.stderr
+++ b/tests/ui/impl-trait/issues/issue-100075-2.stderr
@@ -1,3 +1,9 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-100075-2.rs:1:23
+   |
+LL | fn opaque<T>(t: T) -> impl Sized {
+   |                       ^^^^^^^^^^
+
 warning: function cannot return without recursing
   --> $DIR/issue-100075-2.rs:1:1
    |
@@ -10,15 +16,6 @@ LL |     opaque(Some(t))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0720]: cannot resolve opaque type
-  --> $DIR/issue-100075-2.rs:1:23
-   |
-LL | fn opaque<T>(t: T) -> impl Sized {
-   |                       ^^^^^^^^^^ recursive opaque type
-...
-LL |     opaque(Some(t))
-   |     --------------- returning here with type `impl Sized`
-
 error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/issues/issue-100075.stderr b/tests/ui/impl-trait/issues/issue-100075.stderr
index 75963489236..bca2874b2b4 100644
--- a/tests/ui/impl-trait/issues/issue-100075.stderr
+++ b/tests/ui/impl-trait/issues/issue-100075.stderr
@@ -2,10 +2,7 @@ error[E0720]: cannot resolve opaque type
   --> $DIR/issue-100075.rs:13:37
    |
 LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
-   |                                     ^^^^^^^^^^^ recursive opaque type
-...
-LL |         return _g(t);
-   |                ----- returning here with type `&impl Marker`
+   |                                     ^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/issues/issue-103599.rs b/tests/ui/impl-trait/issues/issue-103599.rs
index 62741a7454c..e674ce3cbdf 100644
--- a/tests/ui/impl-trait/issues/issue-103599.rs
+++ b/tests/ui/impl-trait/issues/issue-103599.rs
@@ -1,9 +1,8 @@
-//@ check-pass
-
 trait T {}
 
 fn wrap(x: impl T) -> impl T {
-    //~^ WARN function cannot return without recursing
+    //~^ ERROR cannot resolve opaque type
+    //~| WARN function cannot return without recursing
     wrap(wrap(x))
 }
 
diff --git a/tests/ui/impl-trait/issues/issue-103599.stderr b/tests/ui/impl-trait/issues/issue-103599.stderr
index 82038c1dceb..9878b12044f 100644
--- a/tests/ui/impl-trait/issues/issue-103599.stderr
+++ b/tests/ui/impl-trait/issues/issue-103599.stderr
@@ -1,14 +1,21 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-103599.rs:3:23
+   |
+LL | fn wrap(x: impl T) -> impl T {
+   |                       ^^^^^^
+
 warning: function cannot return without recursing
-  --> $DIR/issue-103599.rs:5:1
+  --> $DIR/issue-103599.rs:3:1
    |
 LL | fn wrap(x: impl T) -> impl T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
+...
 LL |     wrap(wrap(x))
    |          ------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-warning: 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/issues/issue-87450.rs b/tests/ui/impl-trait/issues/issue-87450.rs
index 983ef7cfbe0..5a7759af111 100644
--- a/tests/ui/impl-trait/issues/issue-87450.rs
+++ b/tests/ui/impl-trait/issues/issue-87450.rs
@@ -3,8 +3,8 @@ fn bar() -> impl Fn() {
 }
 
 fn foo() -> impl Fn() {
-    //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion]
-    //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720]
+    //~^ WARN function cannot return without recursing
+    //~| ERROR cannot resolve opaque type
     wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
 }
 
diff --git a/tests/ui/impl-trait/issues/issue-87450.stderr b/tests/ui/impl-trait/issues/issue-87450.stderr
index 9567e09651d..f0f8b5859c0 100644
--- a/tests/ui/impl-trait/issues/issue-87450.stderr
+++ b/tests/ui/impl-trait/issues/issue-87450.stderr
@@ -1,3 +1,9 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-87450.rs:5:13
+   |
+LL | fn foo() -> impl Fn() {
+   |             ^^^^^^^^^
+
 warning: function cannot return without recursing
   --> $DIR/issue-87450.rs:5:1
    |
@@ -10,18 +16,6 @@ LL |     wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0720]: cannot resolve opaque type
-  --> $DIR/issue-87450.rs:5:13
-   |
-LL | fn foo() -> impl Fn() {
-   |             ^^^^^^^^^ recursive opaque type
-...
-LL |     wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
-   |     ----------------------------------------------- returning here with type `impl Fn()`
-...
-LL | fn wrap(f: impl Fn()) -> impl Fn() {
-   |                          --------- returning this opaque type `impl Fn()`
-
 error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
index 2d2731e4368..af84375c747 100644
--- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
+++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
@@ -2,112 +2,67 @@ error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:6:22
    |
 LL | fn option(i: i32) -> impl Sized {
-   |                      ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
-   |                ----          ------------------------ returning here with type `Option<(impl Sized, i32)>`
-   |                |
-   |                returning here with type `Option<(impl Sized, i32)>`
+   |                      ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:11:15
    |
 LL | fn tuple() -> impl Sized {
-   |               ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     (tuple(),)
-   |     ---------- returning here with type `(impl Sized,)`
+   |               ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:16:15
    |
 LL | fn array() -> impl Sized {
-   |               ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     [array()]
-   |     --------- returning here with type `[impl Sized; 1]`
+   |               ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:21:13
    |
 LL | fn ptr() -> impl Sized {
-   |             ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     &ptr() as *const _
-   |     ------------------ returning here with type `*const impl Sized`
+   |             ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:26:16
    |
 LL | fn fn_ptr() -> impl Sized {
-   |                ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     fn_ptr as fn() -> _
-   |     ------------------- returning here with type `fn() -> impl Sized`
+   |                ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:31:25
    |
-LL |   fn closure_capture() -> impl Sized {
-   |                           ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         x;
-   | |         - closure captures itself here
-LL | |     }
-   | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:34:5: 34:12}`
+LL | fn closure_capture() -> impl Sized {
+   |                         ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:39:29
    |
-LL |   fn closure_ref_capture() -> impl Sized {
-   |                               ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         &x;
-   | |          - closure captures itself here
-LL | |     }
-   | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:42:5: 42:12}`
+LL | fn closure_ref_capture() -> impl Sized {
+   |                             ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:47:21
    |
 LL | fn closure_sig() -> impl Sized {
-   |                     ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     || closure_sig()
-   |     ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:49:5: 49:7}`
+   |                     ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:52:23
    |
 LL | fn coroutine_sig() -> impl Sized {
-   |                       ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     || coroutine_sig()
-   |     ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7}`
+   |                       ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:57:27
    |
-LL |   fn coroutine_capture() -> impl Sized {
-   |                             ^^^^^^^^^^ recursive opaque type
-...
-LL | /     move || {
-LL | |         yield;
-LL | |         x;
-   | |         - coroutine captures itself here
-LL | |     }
-   | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:62:5: 62:12}`
+LL | fn coroutine_capture() -> impl Sized {
+   |                           ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:68:35
    |
 LL | fn substs_change<T: 'static>() -> impl Sized {
-   |                                   ^^^^^^^^^^ recursive opaque type
-LL |
-LL |     (substs_change::<&T>(),)
-   |     ------------------------ returning here with type `(impl Sized,)`
+   |                                   ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:78:26
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
index 42dbc7c9160..080c3284641 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
@@ -1,56 +1,21 @@
-warning: function cannot return without recursing
-  --> $DIR/recursive-in-exhaustiveness.rs:17:1
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-in-exhaustiveness.rs:17:22
    |
 LL | fn build<T>(x: T) -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
-LL |     let (x,) = (build(x),);
-   |                 -------- recursive call site
-   |
-   = help: a `loop` may express intention better if this is on purpose
-   = note: `#[warn(unconditional_recursion)]` on by default
-
-warning: function cannot return without recursing
-  --> $DIR/recursive-in-exhaustiveness.rs:27:1
-   |
-LL | fn build2<T>(x: T) -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-...
-LL |     let (x,) = (build2(x),);
-   |                 --------- recursive call site
-   |
-   = help: a `loop` may express intention better if this is on purpose
+   |                      ^^^^^^^^^^
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-in-exhaustiveness.rs:27:23
    |
 LL | fn build2<T>(x: T) -> impl Sized {
-   |                       ^^^^^^^^^^ recursive opaque type
-...
-LL |     (build2(x),)
-   |     ------------ returning here with type `(impl Sized,)`
+   |                       ^^^^^^^^^^
 
-warning: function cannot return without recursing
-  --> $DIR/recursive-in-exhaustiveness.rs:40:1
-   |
-LL | fn build3<T>(x: T) -> impl Sized {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
-LL |     let (x,) = (build3((x,)),);
-   |                 ------------ recursive call site
-   |
-   = help: a `loop` may express intention better if this is on purpose
-
-error[E0792]: expected generic type parameter, found `(T,)`
-  --> $DIR/recursive-in-exhaustiveness.rs:49:5
+error[E0720]: cannot resolve opaque type
+  --> $DIR/recursive-in-exhaustiveness.rs:39:23
    |
 LL | fn build3<T>(x: T) -> impl Sized {
-   |           - this generic parameter must be used with a generic type parameter
-...
-LL |     build3(x)
-   |     ^^^^^^^^^
+   |                       ^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 3 warnings emitted
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0720, E0792.
-For more information about an error, try `rustc --explain E0720`.
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
index 4c3d5aa8fb8..a3609b93cb3 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -5,19 +5,19 @@ LL |     let (x,) = (build(x),);
    |                 ^^^^^^^^ cannot satisfy `impl Sized == _`
 
 error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:31:6
+  --> $DIR/recursive-in-exhaustiveness.rs:30:6
    |
 LL |     (build2(x),)
    |      ^^^^^^^^^ types differ
 
 error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:31:5
+  --> $DIR/recursive-in-exhaustiveness.rs:30:5
    |
 LL |     (build2(x),)
    |     ^^^^^^^^^^^^ types differ
 
 error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
-  --> $DIR/recursive-in-exhaustiveness.rs:31:5
+  --> $DIR/recursive-in-exhaustiveness.rs:30:5
    |
 LL |     (build2(x),)
    |     ^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -26,13 +26,13 @@ LL |     (build2(x),)
    = note: tuples must have a statically known size to be initialized
 
 error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+  --> $DIR/recursive-in-exhaustiveness.rs:41:17
    |
 LL |     let (x,) = (build3((x,)),);
    |                 ^^^^^^^^^^^^ types differ
 
 error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
-  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+  --> $DIR/recursive-in-exhaustiveness.rs:41:16
    |
 LL |     let (x,) = (build3((x,)),);
    |                ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -41,7 +41,7 @@ LL |     let (x,) = (build3((x,)),);
    = note: tuples must have a statically known size to be initialized
 
 error[E0308]: mismatched types
-  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+  --> $DIR/recursive-in-exhaustiveness.rs:41:16
    |
 LL | fn build3<T>(x: T) -> impl Sized {
    |                       ---------- the found opaque type
@@ -53,7 +53,7 @@ LL |     let (x,) = (build3((x,)),);
              found tuple `(impl Sized,)`
 
 error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+  --> $DIR/recursive-in-exhaustiveness.rs:41:17
    |
 LL |     let (x,) = (build3((x,)),);
    |                 ^^^^^^^^^^^^ types differ
@@ -61,13 +61,13 @@ LL |     let (x,) = (build3((x,)),);
    = note: the return type of a function must have a statically known size
 
 error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:42:16
+  --> $DIR/recursive-in-exhaustiveness.rs:41:16
    |
 LL |     let (x,) = (build3((x,)),);
    |                ^^^^^^^^^^^^^^^ types differ
 
 error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
-  --> $DIR/recursive-in-exhaustiveness.rs:42:17
+  --> $DIR/recursive-in-exhaustiveness.rs:41:17
    |
 LL |     let (x,) = (build3((x,)),);
    |                 ^^^^^^^^^^^^ types differ
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
index 58944533686..fa8fa0e8174 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
@@ -15,7 +15,7 @@
 // We unfortunately accept this today, and due to how opaque type relating is implemented
 // in the NLL type relation, this defines `Opaque<T> = T`.
 fn build<T>(x: T) -> impl Sized {
-    //[current]~^ WARN function cannot return without recursing
+    //[current]~^ ERROR cannot resolve opaque type
     let (x,) = (build(x),);
     //[next]~^ ERROR type annotations needed
     build(x)
@@ -26,7 +26,6 @@ fn build<T>(x: T) -> impl Sized {
 // Not allowed today. Detected as recursive.
 fn build2<T>(x: T) -> impl Sized {
     //[current]~^ ERROR cannot resolve opaque type
-    //[current]~| WARN function cannot return without recursing
     let (x,) = (build2(x),);
     (build2(x),)
     //[next]~^ ERROR type mismatch resolving
@@ -38,7 +37,7 @@ fn build2<T>(x: T) -> impl Sized {
 //
 // Not allowed today. Detected as not defining.
 fn build3<T>(x: T) -> impl Sized {
-    //[current]~^ WARN function cannot return without recursing
+    //[current]~^ ERROR cannot resolve opaque type
     let (x,) = (build3((x,)),);
     //[next]~^ ERROR type mismatch resolving
     //[next]~| ERROR type mismatch resolving
@@ -47,7 +46,6 @@ fn build3<T>(x: T) -> impl Sized {
     //[next]~| ERROR the size for values of type
     //[next]~| ERROR mismatched types
     build3(x)
-    //[current]~^ ERROR expected generic type parameter, found `(T,)`
 }
 
 fn main() {}
diff --git a/tests/ui/issues/issue-18959.rs b/tests/ui/issues/issue-18959.rs
index 6aeb34879ea..dbc73bafce9 100644
--- a/tests/ui/issues/issue-18959.rs
+++ b/tests/ui/issues/issue-18959.rs
@@ -11,7 +11,6 @@ impl Foo for Thing {
 fn foo(b: &dyn Bar) {
     //~^ ERROR E0038
     b.foo(&0)
-    //~^ ERROR E0038
 }
 
 fn main() {
diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr
index 1e050b115e5..7ddfdb49d95 100644
--- a/tests/ui/issues/issue-18959.stderr
+++ b/tests/ui/issues/issue-18959.stderr
@@ -15,23 +15,7 @@ LL | pub trait Bar: Foo { }
    = help: consider moving `foo` to another trait
 
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/issue-18959.rs:13:5
-   |
-LL |     b.foo(&0)
-   |     ^^^^^^^^^ `Bar` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/issue-18959.rs:1:20
-   |
-LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
-   |                    ^^^ ...because method `foo` has generic type parameters
-LL | pub trait Bar: Foo { }
-   |           --- this trait is not dyn compatible...
-   = help: consider moving `foo` to another trait
-
-error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/issue-18959.rs:19:26
+  --> $DIR/issue-18959.rs:18:26
    |
 LL |     let test: &dyn Bar = &mut thing;
    |                          ^^^^^^^^^^ `Bar` is not dyn compatible
@@ -48,7 +32,7 @@ LL | pub trait Bar: Foo { }
    = note: required for the cast from `&mut Thing` to `&dyn Bar`
 
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/issue-18959.rs:19:15
+  --> $DIR/issue-18959.rs:18:15
    |
 LL |     let test: &dyn Bar = &mut thing;
    |               ^^^^^^^^ `Bar` is not dyn compatible
@@ -63,6 +47,6 @@ LL | pub trait Bar: Foo { }
    |           --- this trait is not dyn compatible...
    = help: consider moving `foo` to another trait
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/label/continue-pointing-to-block-ice-113379.rs b/tests/ui/label/continue-pointing-to-block-ice-113379.rs
new file mode 100644
index 00000000000..8a6a9cc8409
--- /dev/null
+++ b/tests/ui/label/continue-pointing-to-block-ice-113379.rs
@@ -0,0 +1,12 @@
+//! Regression test for ICE #113379. Liveness linting assumes that `continue`s all point to loops.
+//! This tests that if a `continue` points to a block, we don't run liveness lints.
+
+async fn f999() -> Vec<usize> {
+    //~^ ERROR `async fn` is not permitted in Rust 2015
+    'b: {
+        //~^ ERROR mismatched types
+        continue 'b;
+        //~^ ERROR `continue` pointing to a labeled block
+    }
+}
+//~^ ERROR `main` function not found
diff --git a/tests/ui/label/continue-pointing-to-block-ice-113379.stderr b/tests/ui/label/continue-pointing-to-block-ice-113379.stderr
new file mode 100644
index 00000000000..ada6305ec99
--- /dev/null
+++ b/tests/ui/label/continue-pointing-to-block-ice-113379.stderr
@@ -0,0 +1,43 @@
+error[E0670]: `async fn` is not permitted in Rust 2015
+  --> $DIR/continue-pointing-to-block-ice-113379.rs:4:1
+   |
+LL | async fn f999() -> Vec<usize> {
+   | ^^^^^ to use `async fn`, switch to Rust 2018 or later
+   |
+   = help: pass `--edition 2024` to `rustc`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0601]: `main` function not found in crate `continue_pointing_to_block_ice_113379`
+  --> $DIR/continue-pointing-to-block-ice-113379.rs:11:2
+   |
+LL | }
+   |  ^ consider adding a `main` function to `$DIR/continue-pointing-to-block-ice-113379.rs`
+
+error[E0696]: `continue` pointing to a labeled block
+  --> $DIR/continue-pointing-to-block-ice-113379.rs:8:9
+   |
+LL | /     'b: {
+LL | |
+LL | |         continue 'b;
+   | |         ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
+LL | |
+LL | |     }
+   | |_____- labeled block the `continue` points to
+
+error[E0308]: mismatched types
+  --> $DIR/continue-pointing-to-block-ice-113379.rs:6:5
+   |
+LL | /     'b: {
+LL | |
+LL | |         continue 'b;
+LL | |
+LL | |     }
+   | |_____^ expected `Vec<usize>`, found `()`
+   |
+   = note: expected struct `Vec<usize>`
+           found unit type `()`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0601, E0670, E0696.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/label/continue-pointing-to-block-ice-121623.rs b/tests/ui/label/continue-pointing-to-block-ice-121623.rs
new file mode 100644
index 00000000000..7047f7a309a
--- /dev/null
+++ b/tests/ui/label/continue-pointing-to-block-ice-121623.rs
@@ -0,0 +1,11 @@
+//! Regression test for ICE #121623. Liveness linting assumes that `continue`s all point to loops.
+//! This tests that if a `continue` points to a block, we don't run liveness lints.
+
+fn main() {
+    match () {
+        _ => 'b: {
+            continue 'b;
+            //~^ ERROR `continue` pointing to a labeled block
+        }
+    }
+}
diff --git a/tests/ui/label/continue-pointing-to-block-ice-121623.stderr b/tests/ui/label/continue-pointing-to-block-ice-121623.stderr
new file mode 100644
index 00000000000..a484fb629d1
--- /dev/null
+++ b/tests/ui/label/continue-pointing-to-block-ice-121623.stderr
@@ -0,0 +1,14 @@
+error[E0696]: `continue` pointing to a labeled block
+  --> $DIR/continue-pointing-to-block-ice-121623.rs:7:13
+   |
+LL |           _ => 'b: {
+   |  ______________-
+LL | |             continue 'b;
+   | |             ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
+LL | |
+LL | |         }
+   | |_________- labeled block the `continue` points to
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0696`.
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs
index 90ed5f3f0ef..7676b5557d2 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.rs
+++ b/tests/ui/lang-items/lang-item-generic-requirements.rs
@@ -49,12 +49,14 @@ fn ice() {
     // Use index
     let arr = [0; 5];
     let _ = arr[2];
+    //~^ ERROR cannot index into a value of type `[{integer}; 5]`
 
     // Use phantomdata
     let _ = MyPhantomData::<(), i32>;
 
     // Use Foo
     let _: () = Foo;
+    //~^ ERROR mismatched types
 }
 
 // use `start`
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr
index 3de67d65940..409fa05d637 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.stderr
+++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr
@@ -76,9 +76,23 @@ LL |     r + a;
    |     |
    |     {integer}
 
+error[E0608]: cannot index into a value of type `[{integer}; 5]`
+  --> $DIR/lang-item-generic-requirements.rs:51:16
+   |
+LL |     let _ = arr[2];
+   |                ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/lang-item-generic-requirements.rs:58:17
+   |
+LL |     let _: () = Foo;
+   |            --   ^^^ expected `()`, found `Foo`
+   |            |
+   |            expected due to this
+
 error: requires `copy` lang_item
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
-Some errors have detailed explanations: E0369, E0392, E0718.
-For more information about an error, try `rustc --explain E0369`.
+Some errors have detailed explanations: E0308, E0369, E0392, E0608, E0718.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index fbb647c37c5..e611abd31f3 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -55,7 +55,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
-   |            ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Assoc>::Ty`
+   |            ^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: Dyn::Ty;
+LL +     let _: <dyn Dyn as Assoc>::Ty;
+   |
 
 error: aborting due to 1 previous error; 4 warnings emitted
 
diff --git a/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
new file mode 100644
index 00000000000..e98d57d1154
--- /dev/null
+++ b/tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
@@ -0,0 +1,110 @@
+//@ run-pass
+//@ needs-unwind
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+
+// See `mir_drop_order.rs` for more information
+
+#![feature(if_let_guard)]
+#![allow(irrefutable_let_patterns)]
+
+use std::cell::RefCell;
+use std::panic;
+
+pub struct DropLogger<'a, T> {
+    extra: T,
+    id: usize,
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>,
+}
+
+impl<'a, T> Drop for DropLogger<'a, T> {
+    fn drop(&mut self) {
+        self.log.0.borrow_mut().push(self.id);
+    }
+}
+
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
+fn main() {
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
+    let d = |id, extra| DropLogger { extra, id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.0.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (
+            d(
+                0,
+                d(
+                    1,
+                    match () { () if let Some(_) = d(2, Some(true)).extra
+                        && let DropLogger { .. } = d(3, None) => {
+                            None
+                        }
+                        _ => {
+                            Some(true)
+                        }
+                    }
+                )
+                .extra,
+            ),
+            d(4, None),
+            &d(5, None),
+            d(6, None),
+            match () {
+                () if let DropLogger { .. } = d(7, None)
+                && let DropLogger { .. } = d(8, None) => {
+                    d(9, None)
+                }
+                _ => {
+                    // 10 is not constructed
+                    d(10, None)
+                }
+            },
+        );
+        assert_eq!(get(), vec![3, 2, 8, 7, 1]);
+    }
+    assert_eq!(get(), vec![0, 4, 6, 9, 5]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (
+            d(
+                11,
+                d(
+                    12,
+                    match () {
+                        () if let Some(_) = d(13, Some(true)).extra
+                                && let DropLogger { .. } = d(14, None) => {
+                            None
+                        }
+                        _ => {
+                            Some(true)
+                        }
+                    }
+                )
+                .extra,
+            ),
+            d(15, None),
+            &d(16, None),
+            d(17, None),
+            match () {
+                () if let DropLogger { .. } = d(18, None)
+                    && let DropLogger { .. } = d(19, None)
+                => {
+                    d(20, None)
+                }
+                _ => {
+                    // 10 is not constructed
+                    d(21, None)
+                }
+            },
+            panic::panic_any(InjectedFailure),
+        );
+    });
+    assert_eq!(get(), vec![14, 13, 19, 18, 20, 17, 15, 11, 16, 12]);
+}
diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr
new file mode 100644
index 00000000000..a2cec972e4a
--- /dev/null
+++ b/tests/ui/mismatched_types/hr-projection-mismatch.current.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/hr-projection-mismatch.rs:20:5
+   |
+LL |     wrap::<_, Thing>();
+   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected reference `&'a _`
+              found reference `&_`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr b/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr
new file mode 100644
index 00000000000..6ea0d43e153
--- /dev/null
+++ b/tests/ui/mismatched_types/hr-projection-mismatch.next.stderr
@@ -0,0 +1,20 @@
+error[E0271]: type mismatch resolving `<Thing as Trait<'a>>::Assoc == &i32`
+  --> $DIR/hr-projection-mismatch.rs:20:15
+   |
+LL |     wrap::<_, Thing>();
+   |               ^^^^^ type mismatch resolving `<Thing as Trait<'a>>::Assoc == &i32`
+   |
+note: types differ
+  --> $DIR/hr-projection-mismatch.rs:14:18
+   |
+LL |     type Assoc = &'a i32;
+   |                  ^^^^^^^
+note: required by a bound in `wrap`
+  --> $DIR/hr-projection-mismatch.rs:17:33
+   |
+LL | fn wrap<T, U: for<'a> Trait<'a, Assoc = T>>() {}
+   |                                 ^^^^^^^^^ required by this bound in `wrap`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/mismatched_types/hr-projection-mismatch.rs b/tests/ui/mismatched_types/hr-projection-mismatch.rs
new file mode 100644
index 00000000000..f96314a3fca
--- /dev/null
+++ b/tests/ui/mismatched_types/hr-projection-mismatch.rs
@@ -0,0 +1,25 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Regression test for <https://github.com/rust-lang/rust/issues/141322>.
+
+trait Trait<'a> {
+    type Assoc;
+}
+
+struct Thing;
+
+impl<'a> Trait<'a> for Thing {
+    type Assoc = &'a i32;
+}
+
+fn wrap<T, U: for<'a> Trait<'a, Assoc = T>>() {}
+
+fn foo() {
+    wrap::<_, Thing>();
+    //[next]~^ ERROR type mismatch resolving `<Thing as Trait<'a>>::Assoc == &i32
+    //[current]~^^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs
index 25de5978110..937e5b82da5 100644
--- a/tests/ui/on-unimplemented/bad-annotation.rs
+++ b/tests/ui/on-unimplemented/bad-annotation.rs
@@ -59,7 +59,7 @@ trait EmptyOn {}
 //~^^^ NOTE expected value here
 trait ExpectedPredicateInOn {}
 
-#[rustc_on_unimplemented(on(x = "y"), message = "y")]
+#[rustc_on_unimplemented(on(Self = "y"), message = "y")]
 trait OnWithoutDirectives {}
 
 #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")]
@@ -107,3 +107,13 @@ trait InvalidPredicate {}
 //~^ ERROR invalid flag in `on`-clause
 //~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something`
 trait InvalidFlag {}
+
+#[rustc_on_unimplemented(on(_Self = "y", message = "y"))]
+//~^ ERROR invalid name in `on`-clause
+//~^^ NOTE expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `_Self`
+trait InvalidName {}
+
+#[rustc_on_unimplemented(on(abc = "y", message = "y"))]
+//~^ ERROR invalid name in `on`-clause
+//~^^ NOTE expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `abc`
+trait InvalidName2 {}
diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr
index 35b919c7b78..3fc54532774 100644
--- a/tests/ui/on-unimplemented/bad-annotation.stderr
+++ b/tests/ui/on-unimplemented/bad-annotation.stderr
@@ -125,7 +125,19 @@ error[E0232]: invalid flag in `on`-clause
 LL | #[rustc_on_unimplemented(on(something, message = "y"))]
    |                             ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something`
 
-error: aborting due to 18 previous errors
+error[E0232]: invalid name in `on`-clause
+  --> $DIR/bad-annotation.rs:111:29
+   |
+LL | #[rustc_on_unimplemented(on(_Self = "y", message = "y"))]
+   |                             ^^^^^ expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `_Self`
+
+error[E0232]: invalid name in `on`-clause
+  --> $DIR/bad-annotation.rs:116:29
+   |
+LL | #[rustc_on_unimplemented(on(abc = "y", message = "y"))]
+   |                             ^^^ expected one of `cause`, `from_desugaring`, `Self` or any generic parameter of the trait, not `abc`
+
+error: aborting due to 20 previous errors
 
 Some errors have detailed explanations: E0230, E0231, E0232.
 For more information about an error, try `rustc --explain E0230`.
diff --git a/tests/ui/on-unimplemented/on-trait.rs b/tests/ui/on-unimplemented/on-trait.rs
index 556813cd479..91630af17e9 100644
--- a/tests/ui/on-unimplemented/on-trait.rs
+++ b/tests/ui/on-unimplemented/on-trait.rs
@@ -3,7 +3,7 @@
 #![feature(rustc_attrs)]
 
 pub mod Bar {
-  #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{Foo}`"]
+  #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}` in `{This}`"]
   pub trait Foo<Bar, Baz, Quux> {}
 }
 
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs b/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs
new file mode 100644
index 00000000000..7bb39ca7bb9
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+//! Test that `GatherLocalsVisitor` only visits expressions in guard patterns when checking the
+//! expressions, and not a second time when visiting the pattern. If locals are declared inside the
+//! the guard expression, it would ICE if visited twice ("evaluated expression more than once").
+
+#![feature(guard_patterns)]
+#![expect(incomplete_features)]
+
+fn main() {
+    match (0,) {
+        // FIXME(guard_patterns): liveness lints don't work yet; this will ICE without the `_`.
+        (_ if { let _x = false; _x },) => {}
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs
new file mode 100644
index 00000000000..7dc9ef7161d
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs
@@ -0,0 +1,12 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/141265>.
+//! Make sure expressions in top-level guard patterns are only resolved once.
+
+fn main() {
+    for
+    else if b 0 {}
+    //~^ ERROR expected identifier, found keyword `else`
+    //~| ERROR missing `in` in `for` loop
+    //~| ERROR cannot find value `b` in this scope
+    //~| ERROR guard patterns are experimental
+    //~| ERROR `{integer}` is not an iterator
+}
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr
new file mode 100644
index 00000000000..dae384137f5
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr
@@ -0,0 +1,48 @@
+error: expected identifier, found keyword `else`
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:5
+   |
+LL |     else if b 0 {}
+   |     ^^^^ expected identifier, found keyword
+
+error: missing `in` in `for` loop
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:14
+   |
+LL |     else if b 0 {}
+   |              ^
+   |
+help: try adding `in` here
+   |
+LL |     else if b in 0 {}
+   |               ++
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13
+   |
+LL |     else if b 0 {}
+   |             ^ not found in this scope
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13
+   |
+LL |     else if b 0 {}
+   |             ^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider using match arm guards
+
+error[E0277]: `{integer}` is not an iterator
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:15
+   |
+LL |     else if b 0 {}
+   |               ^ `{integer}` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `{integer}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required for `{integer}` to implement `IntoIterator`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0277, E0425, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/pattern/unused-parameters-const-pattern.rs b/tests/ui/pattern/unused-parameters-const-pattern.rs
new file mode 100644
index 00000000000..107c65ddfd3
--- /dev/null
+++ b/tests/ui/pattern/unused-parameters-const-pattern.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+// Tests that const patterns that use generic parameters are
+// allowed if we are still able to evaluate them.
+
+trait Trait { const ASSOC: usize; }
+
+impl<T> Trait for T {
+    const ASSOC: usize = 10;
+}
+
+fn foo<T>(a: usize) {
+    match a {
+        <T as Trait>::ASSOC => (),
+        _ => (),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr
index 6641e81013f..e70cdbdc3f4 100644
--- a/tests/ui/qualified/qualified-path-params-2.stderr
+++ b/tests/ui/qualified/qualified-path-params-2.stderr
@@ -7,7 +7,7 @@ LL | type A = <S as Tr>::A::f<u8>;
 help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path
    |
 LL - type A = <S as Tr>::A::f<u8>;
-LL + type A = <<S as Tr>::A as Example>::f;
+LL + type A = <<S as Tr>::A as Example>::f<u8>;
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs
new file mode 100644
index 00000000000..6115146539c
--- /dev/null
+++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.rs
@@ -0,0 +1,72 @@
+#![feature(generic_arg_infer)]
+
+// Test when deferring repeat expr copy checks to end of typechecking whether elements
+// that are const items allow for repeat counts to go uninferred without an error being
+// emitted if they would later wind up inferred by integer fallback.
+//
+// This test should be updated if we wind up deferring repeat expr checks until *after*
+// integer fallback as the point of the test is not *specifically* about integer fallback
+// but rather about the behaviour of `const` element exprs.
+
+trait Trait<const N: usize> {}
+
+// We impl `Trait` for both `i32` and `u32` to avoid being able
+// to prove `?int: Trait<?n>` from there only being one impl.
+impl Trait<2> for i32 {}
+impl Trait<2> for u32 {}
+
+fn tie_and_make_goal<const N: usize, T: Trait<N>>(_: &T, _: &[String; N]) {}
+
+fn const_block() {
+    // Deferred repeat expr `String; ?n`
+    let a = [const { String::new() }; _];
+
+    // `?int: Trait<?n>` goal
+    tie_and_make_goal(&1, &a);
+
+    // If repeat expr checks structurally resolve the `?n`s before checking if the
+    // element is a `const` then we would error here. Otherwise we avoid doing so,
+    // integer fallback occurs, allowing `?int: Trait<?n>` goals to make progress,
+    // inferring the repeat counts (to `2` but that doesn't matter as the element is `const`).
+}
+
+fn const_item() {
+    const MY_CONST: String = String::new();
+
+    // Deferred repeat expr `String; ?n`
+    let a = [MY_CONST; _];
+
+    // `?int: Trait<?n>` goal
+    tie_and_make_goal(&1, &a);
+
+    // ... same as `const_block`
+}
+
+fn assoc_const() {
+    trait Dummy {
+        const ASSOC: String;
+    }
+    impl Dummy for () {
+        const ASSOC: String = String::new();
+    }
+
+    // Deferred repeat expr `String; ?n`
+    let a = [<() as Dummy>::ASSOC; _];
+
+    // `?int: Trait<?n>` goal
+    tie_and_make_goal(&1, &a);
+
+    // ... same as `const_block`
+}
+
+fn const_block_but_uninferred() {
+    // Deferred repeat expr `String; ?n`
+    let a = [const { String::new() }; _];
+    //~^ ERROR: type annotations needed for `[String; _]`
+
+    // Even if we don't structurally resolve the repeat count as part of repeat expr
+    // checks, we still error on the repeat count being uninferred as we require all
+    // types/consts to be inferred by the end of type checking.
+}
+
+fn main() {}
diff --git a/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr
new file mode 100644
index 00000000000..2f52537fa94
--- /dev/null
+++ b/tests/ui/repeat-expr/copy-check-const-element-uninferred-count.stderr
@@ -0,0 +1,15 @@
+error[E0284]: type annotations needed for `[String; _]`
+  --> $DIR/copy-check-const-element-uninferred-count.rs:64:9
+   |
+LL |     let a = [const { String::new() }; _];
+   |         ^   ---------------------------- type must be known at this point
+   |
+   = note: the length of array `[String; _]` must be type `usize`
+help: consider giving `a` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let a: [_; _] = [const { String::new() }; _];
+   |          ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
index d9ad93541ec..3f310f07de0 100644
--- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
+++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.rs
@@ -1,37 +1,53 @@
 #![feature(generic_arg_infer)]
 
-// Test that would start passing if we defer repeat expr copy checks to end of
-// typechecking and they're checked after integer fallback occurs. We accomplish
-// this by contriving a situation where integer fallback allows progress to be
-// made on a trait goal that infers the length of a repeat expr.
+// Test when deferring repeat expr copy checks to end of typechecking whether they're
+// checked before integer fallback occurs or not. We accomplish this by having a repeat
+// count that can only be inferred after integer fallback has occured. This test will
+// pass if we were to check repeat exprs after integer fallback.
 
 use std::marker::PhantomData;
-
-struct NotCopy;
+struct Foo<T>(PhantomData<T>);
+
+// We impl Copy/Clone for multiple (but not all) substitutions
+// to ensure that `Foo<?int>: Copy` can't be proven on the basis
+// of there only being one applying impl.
+impl Clone for Foo<u32> {
+    fn clone(&self) -> Self {
+        Foo(PhantomData)
+    }
+}
+impl Clone for Foo<i32> {
+    fn clone(&self) -> Self {
+        Foo(PhantomData)
+    }
+}
+impl Copy for Foo<u32> {}
+impl Copy for Foo<i32> {}
 
 trait Trait<const N: usize> {}
 
-impl Trait<2> for u32 {}
+// We impl `Trait` for both `i32` and `u32` to avoid being able
+// to prove `?int: Trait<?n>` from there only being one impl.
 impl Trait<1> for i32 {}
+impl Trait<2> for u32 {}
 
-fn make_goal<T: Trait<N>, const N: usize>(_: &T, _: [NotCopy; N]) {}
+fn tie_and_make_goal<const N: usize, T: Trait<N>>(_: &T, _: &[Foo<T>; N]) {}
 
 fn main() {
     let a = 1;
-    let b = [NotCopy; _];
-    //~^ ERROR: type annotations needed
-
-    // a is of type `?y`
-    // b is of type `[NotCopy; ?x]`
-    // there is a goal ?y: Trait<?x>` with two candidates:
-    // - `i32: Trait<1>`, ?y=i32 ?x=1 which doesnt require `NotCopy: Copy`
-    // - `u32: Trait<2>` ?y=u32 ?x=2 which requires `NotCopy: Copy`
-    make_goal(&a, b);
-
-    // final repeat expr checks:
-    //
-    // `NotCopy; ?x`
-    // - succeeds if fallback happens before repeat exprs as `i32: Trait<?x>` infers `?x=1`
-    // - fails if repeat expr checks happen first as `?x` is unconstrained so cannot be
-    //    structurally resolved
+    // Deferred repeat expr `Foo<?int>; ?n`
+    let b = [Foo(PhantomData); _];
+    //~^ ERROR: type annotations needed for `[Foo<{integer}>; _]`
+
+    // Introduces a `?int: Trait<?n>` goal
+    tie_and_make_goal(&a, &b);
+
+    // If fallback doesn't occur:
+    // - `Foo<?int>; ?n`is ambig as repeat count is unknown -> error
+
+    // If fallback occurs:
+    // - `?int` inferred to `i32`
+    // - `?int: Trait<?n>` becomes `i32: Trait<?n>` wihhc infers `?n=1`
+    // - Repeat expr check `Foo<?int>; ?n` is now `Foo<i32>; 1`
+    // - `Foo<i32>; 1` doesn't require `Foo<i32>: Copy`
 }
diff --git a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr
index 2a0cb3fb7a3..103b074dda7 100644
--- a/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr
+++ b/tests/ui/repeat-expr/copy-check-deferred-after-fallback.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for `[NotCopy; _]`
-  --> $DIR/copy-check-deferred-after-fallback.rs:21:9
+error[E0282]: type annotations needed for `[Foo<{integer}>; _]`
+  --> $DIR/copy-check-deferred-after-fallback.rs:39:9
    |
-LL |     let b = [NotCopy; _];
-   |         ^    ------- type must be known at this point
+LL |     let b = [Foo(PhantomData); _];
+   |         ^    ---------------- type must be known at this point
    |
 help: consider giving `b` an explicit type, where the value of const parameter `N` is specified
    |
-LL |     let b: [_; N] = [NotCopy; _];
-   |          ++++++++
+LL |     let b: [Foo<{integer}>; N] = [Foo(PhantomData); _];
+   |          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs
index 4654d7483a6..4fbb8f0a00c 100644
--- a/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs
+++ b/tests/ui/repeat-expr/copy-check-deferred-before-fallback.rs
@@ -1,18 +1,13 @@
 //@ check-pass
-
 #![feature(generic_arg_infer)]
 
-// Test that if we defer repeat expr copy checks to end of typechecking they're
-// checked before integer fallback occurs. We accomplish this by contriving a
-// situation where we have a goal that can be proven either via another repeat expr
-// check or by integer fallback. In the integer fallback case an array length would
-// be inferred to `2` requiring `NotCopy: Copy`, and in the repeat expr case it would
-// be inferred to `1`.
+// Test when deferring repeat expr checks to end of typechecking whether they're
+// checked before integer fallback occurs. We accomplish this by having the repeat
+// expr check allow inference progress on an ambiguous goal, where the ambiguous goal
+// would fail if the inference variable was fallen back to `i32`. This test will
+// pass if we check repeat exprs before integer fallback.
 
 use std::marker::PhantomData;
-
-struct NotCopy;
-
 struct Foo<T>(PhantomData<T>);
 
 impl Clone for Foo<u32> {
@@ -20,40 +15,34 @@ impl Clone for Foo<u32> {
         Foo(PhantomData)
     }
 }
-
 impl Copy for Foo<u32> {}
 
-fn tie<T>(_: &T, _: [Foo<T>; 2]) {}
+trait Trait {}
 
-trait Trait<const N: usize> {}
+// Two impls just to ensure that `?int: Trait` wont itself succeed by unifying with
+// a self type on an impl here. It also ensures that integer fallback would actually
+// be valid for all of the stalled goals incase that's ever something we take into account.
+impl Trait for i32 {}
+impl Trait for u32 {}
 
-impl Trait<2> for i32 {}
-impl Trait<1> for u32 {}
-
-fn make_goal<T: Trait<N>, const N: usize>(_: &T, _: [NotCopy; N]) {}
+fn make_goal<T: Trait>(_: &T) {}
+fn tie<T>(_: &T, _: &[Foo<T>; 2]) {}
 
 fn main() {
     let a = 1;
+    // `?int: Trait`
+    make_goal(&a);
+
+    // Deferred `Foo<?int>: Copy` requirement
     let b: [Foo<_>; 2] = [Foo(PhantomData); _];
-    tie(&a, b);
-    let c = [NotCopy; _];
-
-    // a is of type `?y`
-    // b is of type `[Foo<?y>; 2]`
-    // c is of type `[NotCopy; ?x]`
-    // there is a goal ?y: Trait<?x>` with two candidates:
-    // - `i32: Trait<2>`, ?y=i32 ?x=2 which requires `NotCopy: Copy` when expr checks happen
-    // - `u32: Trait<1>` ?y=u32 ?x=1 which doesnt require `NotCopy: Copy`
-    make_goal(&a, c);
-
-    // final repeat expr checks:
-    //
-    // `Foo<?y>; 2`
-    // - Foo<?y>: Copy
-    // - requires ?y=u32
-    //
-    // `NotCopy; ?x`
-    // - fails if fallback happens before repeat exprs as `i32: Trait<?x>` infers `?x=2`
-    // - succeeds if repeat expr checks happen first as `?y=u32` means `u32: Trait<?x>`
-    //    infers `?x=1`
+    tie(&a, &b);
+
+    // If fallback doesn't occur:
+    // - `Foo<?int>; 2`is > 1, needs copy
+    // - `Foo<?int>: Copy` infers `?int=u32`
+    // - stalled goal `?int: Trait` can now make progress and succeed
+
+    // If fallback occurs:
+    // - `Foo<i32>; 2` is > 1, needs copy
+    // - `Foo<i32>: Copy` doesn't hold -> error
 }
diff --git a/tests/ui/repeat-expr/copy-check-inference-side-effects.rs b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs
new file mode 100644
index 00000000000..4e3bfdead26
--- /dev/null
+++ b/tests/ui/repeat-expr/copy-check-inference-side-effects.rs
@@ -0,0 +1,34 @@
+#![feature(generic_arg_infer)]
+
+struct Foo<const N: usize>;
+
+impl Clone for Foo<1> {
+    fn clone(&self) -> Self {
+        Self
+    }
+}
+impl Copy for Foo<1> {}
+
+fn unify<const N: usize>(_: &[Foo<N>; 2], _: &[String; N]) {}
+
+fn works_if_inference_side_effects() {
+    // This will only pass if inference side effects from proving `Foo<?x>: Copy` are
+    // able to be relied upon by other repeat expressions.
+    let a /* : [Foo<?x>; 2] */ = [Foo::<_>; 2];
+    //~^ ERROR: type annotations needed for `[Foo<_>; 2]`
+    let b /* : [String; ?x] */ = ["string".to_string(); _];
+
+    unify(&a, &b);
+}
+
+fn works_if_fixed_point() {
+    // This will only pass if the *second* array repeat expr is checked first
+    // allowing `Foo<?x>: Copy` to infer the array length of the first repeat expr.
+    let b /* : [String; ?x] */ = ["string".to_string(); _];
+    //~^ ERROR: type annotations needed for `[String; _]`
+    let a /* : [Foo<?x>; 2] */ = [Foo::<_>; 2];
+
+    unify(&a, &b);
+}
+
+fn main() {}
diff --git a/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr b/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr
new file mode 100644
index 00000000000..505beff0f6b
--- /dev/null
+++ b/tests/ui/repeat-expr/copy-check-inference-side-effects.stderr
@@ -0,0 +1,28 @@
+error[E0282]: type annotations needed for `[Foo<_>; 2]`
+  --> $DIR/copy-check-inference-side-effects.rs:17:9
+   |
+LL |     let a /* : [Foo<?x>; 2] */ = [Foo::<_>; 2];
+   |         ^
+LL |
+LL |     let b /* : [String; ?x] */ = ["string".to_string(); _];
+   |                                   -------------------- type must be known at this point
+   |
+help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
+   |
+LL |     let a: [Foo<N>; 2] /* : [Foo<?x>; 2] */ = [Foo::<_>; 2];
+   |          +++++++++++++
+
+error[E0282]: type annotations needed for `[String; _]`
+  --> $DIR/copy-check-inference-side-effects.rs:27:9
+   |
+LL |     let b /* : [String; ?x] */ = ["string".to_string(); _];
+   |         ^                         -------------------- type must be known at this point
+   |
+help: consider giving `b` an explicit type, where the value of const parameter `N` is specified
+   |
+LL |     let b: [_; N] /* : [String; ?x] */ = ["string".to_string(); _];
+   |          ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs
index 0b0672d9c2b..d50466ac4bb 100644
--- a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs
+++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs
@@ -1,8 +1,3 @@
-//@revisions: current gai
-//@[current] check-pass
-
-#![cfg_attr(gai, feature(generic_arg_infer))]
-
 use std::marker::PhantomData;
 
 struct Foo<T>(PhantomData<T>);
@@ -20,6 +15,6 @@ fn extract<T, const N: usize>(_: [Foo<T>; N]) -> T {
 
 fn main() {
     let x = [Foo(PhantomData); 2];
-    //[gai]~^ ERROR: type annotations needed
-    _ = extract(x).max(2);
+    //~^ ERROR: type annotations needed
+    extract(x).max(2);
 }
diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr
new file mode 100644
index 00000000000..ba44beb76db
--- /dev/null
+++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr
@@ -0,0 +1,17 @@
+error[E0282]: type annotations needed for `[Foo<_>; 2]`
+  --> $DIR/copy-inference-side-effects-are-lazy.rs:17:9
+   |
+LL |     let x = [Foo(PhantomData); 2];
+   |         ^
+LL |
+LL |     extract(x).max(2);
+   |     ---------- type must be known at this point
+   |
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+   |
+LL |     let x: [Foo<T>; 2] = [Foo(PhantomData); 2];
+   |          +++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs
new file mode 100644
index 00000000000..d2aa61186bc
--- /dev/null
+++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.rs
@@ -0,0 +1,15 @@
+struct Foo {
+    x: i32
+}
+
+impl Foo {
+    fn foo(&self) {
+        let _ = format!("{x}"); //~ ERROR cannot find value `x` in this scope [E0425]
+        let _ = format!("{x }"); //~ ERROR cannot find value `x` in this scope [E0425]
+        let _ = format!("{ x}"); //~ ERROR invalid format string: expected `}`, found `x`
+        let _ = format!("{}", x); //~ ERROR cannot find value `x` in this scope [E0425]
+        println!("{x}"); //~ ERROR cannot find value `x` in this scope [E0425]
+    }
+}
+
+fn main(){}
diff --git a/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr
new file mode 100644
index 00000000000..0a84848081d
--- /dev/null
+++ b/tests/ui/resolve/suggestions/sugg-field-in-format-string-issue-141136.stderr
@@ -0,0 +1,48 @@
+error: invalid format string: expected `}`, found `x`
+  --> $DIR/sugg-field-in-format-string-issue-141136.rs:9:28
+   |
+LL |         let _ = format!("{ x}");
+   |                          - ^ expected `}` in format string
+   |                          |
+   |                          because of this opening brace
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/sugg-field-in-format-string-issue-141136.rs:7:27
+   |
+LL |         let _ = format!("{x}");
+   |                           ^
+   |
+   = help: you might have meant to use the available field in a format string: `"{}", self.x`
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/sugg-field-in-format-string-issue-141136.rs:8:27
+   |
+LL |         let _ = format!("{x }");
+   |                           ^^
+   |
+   = help: you might have meant to use the available field in a format string: `"{}", self.x`
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/sugg-field-in-format-string-issue-141136.rs:10:31
+   |
+LL |         let _ = format!("{}", x);
+   |                               ^
+   |
+help: you might have meant to use the available field
+   |
+LL |         let _ = format!("{}", self.x);
+   |                               +++++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/sugg-field-in-format-string-issue-141136.rs:11:20
+   |
+LL |         println!("{x}");
+   |                    ^
+   |
+   = help: you might have meant to use the available field in a format string: `"{}", self.x`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
index 5832cb69a3d..1ecbfee17bc 100644
--- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
+++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.stderr
@@ -20,17 +20,9 @@ error[E0425]: cannot find value `config` in this scope
   --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:15:20
    |
 LL |         println!("{config}");
-   |                    ^^^^^^
-   |
-help: you might have meant to use the available field
-   |
-LL |         println!("{self.config}");
-   |                    +++++
-help: a local variable with a similar name exists
-   |
-LL -         println!("{config}");
-LL +         println!("{cofig}");
+   |                    ^^^^^^ help: a local variable with a similar name exists: `cofig`
    |
+   = help: you might have meant to use the available field in a format string: `"{}", self.config`
 
 error[E0425]: cannot find value `bah` in this scope
   --> $DIR/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs:33:9
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs
new file mode 100644
index 00000000000..9edbc3243c7
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/temporary-early-drop.rs
@@ -0,0 +1,29 @@
+// issue-103476
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ check-pass
+
+#![feature(if_let_guard)]
+#![allow(irrefutable_let_patterns)]
+
+struct Pd;
+
+impl Pd {
+    fn it(&self) -> It {
+        todo!()
+    }
+}
+
+pub struct It<'a>(Box<dyn Tr<'a>>);
+
+trait Tr<'a> {}
+
+fn f(m: Option<Pd>) {
+    match () {
+        () if let Some(n) = m && let it = n.it() => {}
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs
new file mode 100644
index 00000000000..af35d1e0359
--- /dev/null
+++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.rs
@@ -0,0 +1,18 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/141419>.
+
+use std::ops::Deref;
+
+struct W;
+
+trait Foo: Deref<Target = W> {
+    fn method(self: &W) {}
+    //~^ ERROR invalid `self` parameter type: `&W`
+}
+
+fn test(x: &dyn Foo) {
+    //~^ ERROR the trait `Foo` is not dyn compatible
+    x.method();
+    //~^ ERROR the trait `Foo` is not dyn compatible
+}
+
+fn main() {}
diff --git a/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr
new file mode 100644
index 00000000000..237bbc56715
--- /dev/null
+++ b/tests/ui/self/dispatch-dyn-incompatible-that-does-not-deref.stderr
@@ -0,0 +1,49 @@
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:12:13
+   |
+LL |     fn method(self: &W) {}
+   |                     -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
+...
+LL | fn test(x: &dyn Foo) {
+   |             ^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
+   |
+LL | trait Foo: Deref<Target = W> {
+   |       --- this trait is not dyn compatible...
+LL |     fn method(self: &W) {}
+   |                     ^^ ...because method `method`'s `self` parameter cannot be dispatched on
+
+error[E0307]: invalid `self` parameter type: `&W`
+  --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
+   |
+LL |     fn method(self: &W) {}
+   |                     ^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:5
+   |
+LL |     fn method(self: &W) {}
+   |                     -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     x.method();
+   |     ^^^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
+   |
+LL | trait Foo: Deref<Target = W> {
+   |       --- this trait is not dyn compatible...
+LL |     fn method(self: &W) {}
+   |                     ^^ ...because method `method`'s `self` parameter cannot be dispatched on
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0038, E0307.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr
index 18ffd15427f..1bda307d0eb 100644
--- a/tests/ui/self/self-impl.stderr
+++ b/tests/ui/self/self-impl.stderr
@@ -2,13 +2,25 @@ error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:23:16
    |
 LL |         let _: <Self>::Baz = true;
-   |                ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Foo>::Baz`
+   |                ^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         let _: <Self>::Baz = true;
+LL +         let _: <Bar as Foo>::Baz = true;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:25:16
    |
 LL |         let _: Self::Baz = true;
-   |                ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Foo>::Baz`
+   |                ^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         let _: Self::Baz = true;
+LL +         let _: <Bar as Foo>::Baz = true;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr
index de396e875b0..110362293ac 100644
--- a/tests/ui/structs/struct-path-associated-type.stderr
+++ b/tests/ui/structs/struct-path-associated-type.stderr
@@ -48,19 +48,37 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
    |
 LL |     let s = S::A {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Tr>::A`
+   |             ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let s = S::A {};
+LL +     let s = <S as Tr>::A {};
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:33:13
    |
 LL |     let z = S::A::<u8> {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Tr>::A`
+   |             ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let z = S::A::<u8> {};
+LL +     let z = <S as Tr>::A::<u8> {};
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:35:9
    |
 LL |         S::A {} => {}
-   |         ^^^^ help: use fully-qualified syntax: `<S as Tr>::A`
+   |         ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -         S::A {} => {}
+LL +         <S as Tr>::A {} => {}
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs
new file mode 100644
index 00000000000..270874a9f58
--- /dev/null
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: --crate-type=lib
+//@ compile-flags: --target=aarch64-unknown-none-softfloat
+//@ needs-llvm-components: aarch64
+#![feature(no_core, lang_items)]
+#![no_core]
+#![deny(aarch64_softfloat_neon)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[target_feature(enable = "neon")]
+//~^ERROR: enabling the `neon` target feature on the current target is unsound
+//~|WARN: previously accepted
+pub unsafe fn my_fun() {}
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr
new file mode 100644
index 00000000000..bf745291a5a
--- /dev/null
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr
@@ -0,0 +1,31 @@
+error: enabling the `neon` target feature on the current target is unsound due to ABI issues
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
+   |
+LL | #[target_feature(enable = "neon")]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #134375 <https://github.com/rust-lang/rust/issues/134375>
+note: the lint level is defined here
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:6:9
+   |
+LL | #![deny(aarch64_softfloat_neon)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+Future incompatibility report: Future breakage diagnostic:
+error: enabling the `neon` target feature on the current target is unsound due to ABI issues
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
+   |
+LL | #[target_feature(enable = "neon")]
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #134375 <https://github.com/rust-lang/rust/issues/134375>
+note: the lint level is defined here
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:6:9
+   |
+LL | #![deny(aarch64_softfloat_neon)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index 4fd9ef91192..1d3d8cb9843 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -230,13 +230,25 @@ error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:119:12
    |
 LL |     let _: S::B;
-   |            ^^^^ help: use fully-qualified syntax: `<S as assoc_ty::B>::B`
+   |            ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::B;
+LL +     let _: <S as assoc_ty::B>::B;
+   |
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:120:12
    |
 LL |     let _: S::C;
-   |            ^^^^ help: use fully-qualified syntax: `<S as assoc_ty::C>::C`
+   |            ^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     let _: S::C;
+LL +     let _: <S as assoc_ty::C>::C;
+   |
 
 error[E0624]: associated type `A` is private
   --> $DIR/item-privacy.rs:122:12
diff --git a/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs b/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs
new file mode 100644
index 00000000000..8b153833e3a
--- /dev/null
+++ b/tests/ui/traits/next-solver/assembly/better_any-backcompat.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+// A regression test for trait-system-refactor-initiative#183. While
+// this concrete instance is likely not practically unsound, the general
+// pattern is, see #57893.
+
+use std::any::TypeId;
+
+unsafe trait TidAble<'a>: Tid<'a> {}
+trait TidExt<'a>: Tid<'a> {
+    fn downcast_box(self: Box<Self>) {
+        loop {}
+    }
+}
+
+impl<'a, X: ?Sized + Tid<'a>> TidExt<'a> for X {}
+
+unsafe trait Tid<'a>: 'a {}
+
+unsafe impl<'a, T: ?Sized + TidAble<'a>> Tid<'a> for T {}
+
+impl<'a> dyn Tid<'a> + 'a {
+    fn downcast_any_box(self: Box<Self>) {
+        self.downcast_box();
+    }
+}
+
+unsafe impl<'a> TidAble<'a> for dyn Tid<'a> + 'a {}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs b/tests/ui/traits/next-solver/coercion/coerce-ambig-alias-to-rigid-alias.rs
index cc78dc20eaf..cc78dc20eaf 100644
--- a/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs
+++ b/tests/ui/traits/next-solver/coercion/coerce-ambig-alias-to-rigid-alias.rs
diff --git a/tests/ui/traits/next-solver/coerce-depth.rs b/tests/ui/traits/next-solver/coercion/coerce-depth.rs
index c8fc3fcab59..c8fc3fcab59 100644
--- a/tests/ui/traits/next-solver/coerce-depth.rs
+++ b/tests/ui/traits/next-solver/coercion/coerce-depth.rs
diff --git a/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs b/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs
new file mode 100644
index 00000000000..1b5abcb02f2
--- /dev/null
+++ b/tests/ui/traits/next-solver/coercion/fn-def-coerce-nested-obligations.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Make sure that we consider nested obligations when checking whether
+// we should coerce fn definitions to function pointers.
+
+fn foo<const N: usize>() {}
+fn bar<T>() {}
+fn main() {
+    let _ = if true { foo::<{ 0 + 0 }> } else { foo::<1> };
+    let _ = if true {
+        bar::<for<'a> fn(<Vec<&'a ()> as IntoIterator>::Item)>
+    } else {
+        bar::<fn(i32)>
+    };
+}
diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs
index d05def2cb75..d05def2cb75 100644
--- a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs
+++ b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.rs
diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr
index 72be10367da..72be10367da 100644
--- a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr
+++ b/tests/ui/traits/next-solver/coercion/non-wf-in-coerce-pointers.stderr
diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/coercion/trait-upcast-lhs-needs-normalization.rs
index c6094b45775..c6094b45775 100644
--- a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs
+++ b/tests/ui/traits/next-solver/coercion/trait-upcast-lhs-needs-normalization.rs
diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/coercion/upcast-right-substs.rs
index 7a566b59b83..7a566b59b83 100644
--- a/tests/ui/traits/next-solver/upcast-right-substs.rs
+++ b/tests/ui/traits/next-solver/coercion/upcast-right-substs.rs
diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.rs b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.rs
index 473977c527c..473977c527c 100644
--- a/tests/ui/traits/next-solver/upcast-wrong-substs.rs
+++ b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.rs
diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.stderr b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.stderr
index 00ba1ef678f..00ba1ef678f 100644
--- a/tests/ui/traits/next-solver/upcast-wrong-substs.stderr
+++ b/tests/ui/traits/next-solver/coercion/upcast-wrong-substs.stderr
diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs
new file mode 100644
index 00000000000..ffb99d6d638
--- /dev/null
+++ b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env-2.rs
@@ -0,0 +1,29 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>.
+// See comment below.
+
+trait A {
+    fn hello(&self) {}
+}
+
+trait B {
+    fn hello(&self) {}
+}
+
+impl<T> A for T {}
+impl<T> B for T {}
+
+fn test<F, R>(q: F::Item)
+where
+    F: Iterator<Item = R>,
+    // We want to prefer `A` for `R.hello()`
+    F::Item: A,
+{
+    q.hello();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs
new file mode 100644
index 00000000000..dde4f745879
--- /dev/null
+++ b/tests/ui/traits/next-solver/method/param-method-from-unnormalized-param-env.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/214>.
+
+fn execute<K, F, R>(q: F::Item) -> R
+where
+    F: Iterator<Item = R>,
+    // Both of the below bounds should be considered for `.into()`, and then be combined
+    // into a single `R: Into<?0>` bound which can be inferred to `?0 = R`.
+    F::Item: Into<K>,
+    R: Into<String>,
+{
+    q.into()
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/no-param-env-const-fold.rs b/tests/ui/traits/next-solver/no-param-env-const-fold.rs
new file mode 100644
index 00000000000..4f47332dd23
--- /dev/null
+++ b/tests/ui/traits/next-solver/no-param-env-const-fold.rs
@@ -0,0 +1,10 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/213>.
+
+use std::ops::Deref;
+
+trait Trait: Deref<Target = [u8; { 1 + 1 }]> {}
+
+fn main() {}
diff --git a/tests/ui/traits/test-2.rs b/tests/ui/traits/test-2.rs
index ffb778a0141..4ee880da87a 100644
--- a/tests/ui/traits/test-2.rs
+++ b/tests/ui/traits/test-2.rs
@@ -13,5 +13,4 @@ fn main() {
     (Box::new(10) as Box<dyn bar>).dup();
     //~^ ERROR E0038
     //~| ERROR E0038
-    //~| ERROR E0038
 }
diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr
index 6a6cb503aa4..b52839c300e 100644
--- a/tests/ui/traits/test-2.stderr
+++ b/tests/ui/traits/test-2.stderr
@@ -50,29 +50,6 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
            implementing `bar` for this new enum and using it instead
 
 error[E0038]: the trait `bar` is not dyn compatible
-  --> $DIR/test-2.rs:13:5
-   |
-LL |     (Box::new(10) as Box<dyn bar>).dup();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/test-2.rs:4:30
-   |
-LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
-   |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
-   |       |                      |
-   |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait is not dyn compatible...
-   = help: consider moving `dup` to another trait
-   = help: consider moving `blah` to another trait
-   = help: the following types implement `bar`:
-             i32
-             u32
-           consider defining an enum where each variant holds one of these types,
-           implementing `bar` for this new enum and using it instead
-
-error[E0038]: the trait `bar` is not dyn compatible
   --> $DIR/test-2.rs:13:6
    |
 LL |     (Box::new(10) as Box<dyn bar>).dup();
@@ -96,7 +73,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
            implementing `bar` for this new enum and using it instead
    = note: required for the cast from `Box<{integer}>` to `Box<dyn bar>`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0038, E0107.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/transmute/unnecessary-transmutation.fixed b/tests/ui/transmute/unnecessary-transmutation.fixed
index bf7d769348a..08010ec8b84 100644
--- a/tests/ui/transmute/unnecessary-transmutation.fixed
+++ b/tests/ui/transmute/unnecessary-transmutation.fixed
@@ -8,7 +8,27 @@ pub fn bytes_at_home(x: u32) -> [u8; 4] {
     //~^ ERROR
 }
 
+pub const fn intinator_const(from: bool) -> u8 {
+    unsafe { (from) as u8 }
+    //~^ ERROR
+}
+
+pub static X: u8 = unsafe { (true) as u8 };
+//~^ ERROR
+pub const Y: u8 = unsafe { (true) as u8 };
+//~^ ERROR
+
+pub struct Z {}
+impl Z {
+    pub const fn intinator_assoc(x: bool) -> u8 {
+        unsafe { (x) as u8 }
+        //~^ ERROR
+    }
+}
+
 fn main() {
+    const { unsafe { (true) as u8 } };
+    //~^ ERROR
     unsafe {
         let x: u16 = u16::from_ne_bytes(*b"01");
         //~^ ERROR
@@ -81,14 +101,14 @@ fn main() {
         let y: i64 = f64::to_bits(1f64).cast_signed();
         //~^ ERROR
 
-        let z: bool = (1u8 == 1);
-        //~^ ERROR
-        let z: u8 = (z) as u8;
+        let z: bool = transmute(1u8);
+        // clippy
+        let z: u8 = u8::from(z);
         //~^ ERROR
 
         let z: bool = transmute(1i8);
-        // no error!
-        let z: i8 = (z) as i8;
+        // clippy
+        let z: i8 = i8::from(z);
         //~^ ERROR
     }
 }
diff --git a/tests/ui/transmute/unnecessary-transmutation.rs b/tests/ui/transmute/unnecessary-transmutation.rs
index b9de529f1cc..43eefb97dc2 100644
--- a/tests/ui/transmute/unnecessary-transmutation.rs
+++ b/tests/ui/transmute/unnecessary-transmutation.rs
@@ -8,7 +8,27 @@ pub fn bytes_at_home(x: u32) -> [u8; 4] {
     //~^ ERROR
 }
 
+pub const fn intinator_const(from: bool) -> u8 {
+    unsafe { transmute(from) }
+    //~^ ERROR
+}
+
+pub static X: u8 = unsafe { transmute(true) };
+//~^ ERROR
+pub const Y: u8 = unsafe { transmute(true) };
+//~^ ERROR
+
+pub struct Z {}
+impl Z {
+    pub const fn intinator_assoc(x: bool) -> u8 {
+        unsafe { transmute(x) }
+        //~^ ERROR
+    }
+}
+
 fn main() {
+    const { unsafe { transmute::<_, u8>(true) } };
+    //~^ ERROR
     unsafe {
         let x: u16 = transmute(*b"01");
         //~^ ERROR
@@ -82,12 +102,12 @@ fn main() {
         //~^ ERROR
 
         let z: bool = transmute(1u8);
-        //~^ ERROR
+        // clippy
         let z: u8 = transmute(z);
         //~^ ERROR
 
         let z: bool = transmute(1i8);
-        // no error!
+        // clippy
         let z: i8 = transmute(z);
         //~^ ERROR
     }
diff --git a/tests/ui/transmute/unnecessary-transmutation.stderr b/tests/ui/transmute/unnecessary-transmutation.stderr
index a19f1bebf16..602e964f5b2 100644
--- a/tests/ui/transmute/unnecessary-transmutation.stderr
+++ b/tests/ui/transmute/unnecessary-transmutation.stderr
@@ -1,10 +1,9 @@
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:7:14
+  --> $DIR/unnecessary-transmutation.rs:16:29
    |
-LL |     unsafe { transmute(x) }
-   |              ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
+LL | pub static X: u8 = unsafe { transmute(true) };
+   |                             ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
    |
-   = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 note: the lint level is defined here
   --> $DIR/unnecessary-transmutation.rs:2:9
    |
@@ -12,7 +11,33 @@ LL | #![deny(unnecessary_transmutes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:13:22
+  --> $DIR/unnecessary-transmutation.rs:18:28
+   |
+LL | pub const Y: u8 = unsafe { transmute(true) };
+   |                            ^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
+
+error: unnecessary transmute
+  --> $DIR/unnecessary-transmutation.rs:7:14
+   |
+LL |     unsafe { transmute(x) }
+   |              ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
+   |
+   = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
+
+error: unnecessary transmute
+  --> $DIR/unnecessary-transmutation.rs:12:14
+   |
+LL |     unsafe { transmute(from) }
+   |              ^^^^^^^^^^^^^^^ help: replace this with: `(from) as u8`
+
+error: unnecessary transmute
+  --> $DIR/unnecessary-transmutation.rs:24:18
+   |
+LL |         unsafe { transmute(x) }
+   |                  ^^^^^^^^^^^^ help: replace this with: `(x) as u8`
+
+error: unnecessary transmute
+  --> $DIR/unnecessary-transmutation.rs:33:22
    |
 LL |         let x: u16 = transmute(*b"01");
    |                      ^^^^^^^^^^^^^^^^^ help: replace this with: `u16::from_ne_bytes(*b"01")`
@@ -20,7 +45,7 @@ LL |         let x: u16 = transmute(*b"01");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:15:26
+  --> $DIR/unnecessary-transmutation.rs:35:26
    |
 LL |         let x: [u8; 2] = transmute(x);
    |                          ^^^^^^^^^^^^ help: replace this with: `u16::to_ne_bytes(x)`
@@ -28,7 +53,7 @@ LL |         let x: [u8; 2] = transmute(x);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:17:22
+  --> $DIR/unnecessary-transmutation.rs:37:22
    |
 LL |         let x: u32 = transmute(*b"0123");
    |                      ^^^^^^^^^^^^^^^^^^^ help: replace this with: `u32::from_ne_bytes(*b"0123")`
@@ -36,7 +61,7 @@ LL |         let x: u32 = transmute(*b"0123");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:19:26
+  --> $DIR/unnecessary-transmutation.rs:39:26
    |
 LL |         let x: [u8; 4] = transmute(x);
    |                          ^^^^^^^^^^^^ help: replace this with: `u32::to_ne_bytes(x)`
@@ -44,7 +69,7 @@ LL |         let x: [u8; 4] = transmute(x);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:21:22
+  --> $DIR/unnecessary-transmutation.rs:41:22
    |
 LL |         let x: u64 = transmute(*b"feriscat");
    |                      ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `u64::from_ne_bytes(*b"feriscat")`
@@ -52,7 +77,7 @@ LL |         let x: u64 = transmute(*b"feriscat");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:23:26
+  --> $DIR/unnecessary-transmutation.rs:43:26
    |
 LL |         let x: [u8; 8] = transmute(x);
    |                          ^^^^^^^^^^^^ help: replace this with: `u64::to_ne_bytes(x)`
@@ -60,7 +85,7 @@ LL |         let x: [u8; 8] = transmute(x);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:26:22
+  --> $DIR/unnecessary-transmutation.rs:46:22
    |
 LL |         let y: i16 = transmute(*b"01");
    |                      ^^^^^^^^^^^^^^^^^ help: replace this with: `i16::from_ne_bytes(*b"01")`
@@ -68,7 +93,7 @@ LL |         let y: i16 = transmute(*b"01");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:28:26
+  --> $DIR/unnecessary-transmutation.rs:48:26
    |
 LL |         let y: [u8; 2] = transmute(y);
    |                          ^^^^^^^^^^^^ help: replace this with: `i16::to_ne_bytes(y)`
@@ -76,7 +101,7 @@ LL |         let y: [u8; 2] = transmute(y);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:30:22
+  --> $DIR/unnecessary-transmutation.rs:50:22
    |
 LL |         let y: i32 = transmute(*b"0123");
    |                      ^^^^^^^^^^^^^^^^^^^ help: replace this with: `i32::from_ne_bytes(*b"0123")`
@@ -84,7 +109,7 @@ LL |         let y: i32 = transmute(*b"0123");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:32:26
+  --> $DIR/unnecessary-transmutation.rs:52:26
    |
 LL |         let y: [u8; 4] = transmute(y);
    |                          ^^^^^^^^^^^^ help: replace this with: `i32::to_ne_bytes(y)`
@@ -92,7 +117,7 @@ LL |         let y: [u8; 4] = transmute(y);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:34:22
+  --> $DIR/unnecessary-transmutation.rs:54:22
    |
 LL |         let y: i64 = transmute(*b"feriscat");
    |                      ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `i64::from_ne_bytes(*b"feriscat")`
@@ -100,7 +125,7 @@ LL |         let y: i64 = transmute(*b"feriscat");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:36:26
+  --> $DIR/unnecessary-transmutation.rs:56:26
    |
 LL |         let y: [u8; 8] = transmute(y);
    |                          ^^^^^^^^^^^^ help: replace this with: `i64::to_ne_bytes(y)`
@@ -108,7 +133,7 @@ LL |         let y: [u8; 8] = transmute(y);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:39:22
+  --> $DIR/unnecessary-transmutation.rs:59:22
    |
 LL |         let z: f32 = transmute(*b"0123");
    |                      ^^^^^^^^^^^^^^^^^^^ help: replace this with: `f32::from_ne_bytes(*b"0123")`
@@ -116,7 +141,7 @@ LL |         let z: f32 = transmute(*b"0123");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:41:26
+  --> $DIR/unnecessary-transmutation.rs:61:26
    |
 LL |         let z: [u8; 4] = transmute(z);
    |                          ^^^^^^^^^^^^ help: replace this with: `f32::to_ne_bytes(z)`
@@ -124,7 +149,7 @@ LL |         let z: [u8; 4] = transmute(z);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:43:22
+  --> $DIR/unnecessary-transmutation.rs:63:22
    |
 LL |         let z: f64 = transmute(*b"feriscat");
    |                      ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `f64::from_ne_bytes(*b"feriscat")`
@@ -132,7 +157,7 @@ LL |         let z: f64 = transmute(*b"feriscat");
    = help: there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:45:26
+  --> $DIR/unnecessary-transmutation.rs:65:26
    |
 LL |         let z: [u8; 8] = transmute(z);
    |                          ^^^^^^^^^^^^ help: replace this with: `f64::to_ne_bytes(z)`
@@ -140,13 +165,13 @@ LL |         let z: [u8; 8] = transmute(z);
    = help: there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:48:22
+  --> $DIR/unnecessary-transmutation.rs:68:22
    |
 LL |         let y: u32 = transmute('🦀');
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🦀')`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:50:23
+  --> $DIR/unnecessary-transmutation.rs:70:23
    |
 LL |         let y: char = transmute(y);
    |                       ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(y)`
@@ -154,13 +179,13 @@ LL |         let y: char = transmute(y);
    = help: consider `char::from_u32(…).unwrap()`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:52:22
+  --> $DIR/unnecessary-transmutation.rs:72:22
    |
 LL |         let y: i32 = transmute('🐱');
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `u32::from('🐱').cast_signed()`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:54:23
+  --> $DIR/unnecessary-transmutation.rs:74:23
    |
 LL |         let y: char = transmute(y);
    |                       ^^^^^^^^^^^^ help: replace this with: `char::from_u32_unchecked(i32::cast_unsigned(y))`
@@ -168,94 +193,94 @@ LL |         let y: char = transmute(y);
    = help: consider `char::from_u32(i32::cast_unsigned(…)).unwrap()`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:57:22
+  --> $DIR/unnecessary-transmutation.rs:77:22
    |
 LL |         let x: u16 = transmute(8i16);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `i16::cast_unsigned(8i16)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:59:22
+  --> $DIR/unnecessary-transmutation.rs:79:22
    |
 LL |         let x: i16 = transmute(x);
    |                      ^^^^^^^^^^^^ help: replace this with: `u16::cast_signed(x)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:61:22
+  --> $DIR/unnecessary-transmutation.rs:81:22
    |
 LL |         let x: u32 = transmute(4i32);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `i32::cast_unsigned(4i32)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:63:22
+  --> $DIR/unnecessary-transmutation.rs:83:22
    |
 LL |         let x: i32 = transmute(x);
    |                      ^^^^^^^^^^^^ help: replace this with: `u32::cast_signed(x)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:65:22
+  --> $DIR/unnecessary-transmutation.rs:85:22
    |
 LL |         let x: u64 = transmute(7i64);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `i64::cast_unsigned(7i64)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:67:22
+  --> $DIR/unnecessary-transmutation.rs:87:22
    |
 LL |         let x: i64 = transmute(x);
    |                      ^^^^^^^^^^^^ help: replace this with: `u64::cast_signed(x)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:70:22
+  --> $DIR/unnecessary-transmutation.rs:90:22
    |
 LL |         let y: f32 = transmute(1u32);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `f32::from_bits(1u32)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:72:22
+  --> $DIR/unnecessary-transmutation.rs:92:22
    |
 LL |         let y: u32 = transmute(y);
    |                      ^^^^^^^^^^^^ help: replace this with: `f32::to_bits(y)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:74:22
+  --> $DIR/unnecessary-transmutation.rs:94:22
    |
 LL |         let y: f64 = transmute(3u64);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(3u64)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:76:22
+  --> $DIR/unnecessary-transmutation.rs:96:22
    |
 LL |         let y: u64 = transmute(2.0);
    |                      ^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(2.0)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:79:22
+  --> $DIR/unnecessary-transmutation.rs:99:22
    |
 LL |         let y: f64 = transmute(1i64);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `f64::from_bits(i64::cast_unsigned(1i64))`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:81:22
+  --> $DIR/unnecessary-transmutation.rs:101:22
    |
 LL |         let y: i64 = transmute(1f64);
    |                      ^^^^^^^^^^^^^^^ help: replace this with: `f64::to_bits(1f64).cast_signed()`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:84:23
+  --> $DIR/unnecessary-transmutation.rs:106:21
    |
-LL |         let z: bool = transmute(1u8);
-   |                       ^^^^^^^^^^^^^^ help: replace this with: `(1u8 == 1)`
+LL |         let z: u8 = transmute(z);
+   |                     ^^^^^^^^^^^^ help: replace this with: `u8::from(z)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:86:21
+  --> $DIR/unnecessary-transmutation.rs:111:21
    |
-LL |         let z: u8 = transmute(z);
-   |                     ^^^^^^^^^^^^ help: replace this with: `(z) as u8`
+LL |         let z: i8 = transmute(z);
+   |                     ^^^^^^^^^^^^ help: replace this with: `i8::from(z)`
 
 error: unnecessary transmute
-  --> $DIR/unnecessary-transmutation.rs:91:21
+  --> $DIR/unnecessary-transmutation.rs:30:22
    |
-LL |         let z: i8 = transmute(z);
-   |                     ^^^^^^^^^^^^ help: replace this with: `(z) as i8`
+LL |     const { unsafe { transmute::<_, u8>(true) } };
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `(true) as u8`
 
-error: aborting due to 36 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
index 9fcb26c20a6..81be8c8362e 100644
--- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr
+++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
@@ -62,6 +62,11 @@ LL | / fn foo() -> Bar
 LL | | where
 LL | |     Bar: Send,
    | |______________^
+note: ...which requires computing revealed normalized predicates of `foo::{constant#0}`...
+  --> $DIR/in-where-clause.rs:13:9
+   |
+LL |     [0; 1 + 2]
+   |         ^^^^^
    = note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(<Bar as core::marker::Send>, polarity:Positive), bound_vars: [] }]`...
 note: ...which requires computing type of `Bar::{opaque#0}`...
   --> $DIR/in-where-clause.rs:5:12
diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
index ef6871bec7c..0aaee5d1764 100644
--- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
+++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
@@ -1,10 +1,10 @@
 #![feature(type_alias_impl_trait)]
 
 type T = impl Copy;
-//~^ ERROR cannot resolve opaque type
 
 #[define_opaque(T)]
 fn foo() -> T {
+    //~^ ERROR cannot resolve opaque type
     None::<&'static T>
 }
 
diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
index d820df472f9..426a6c29fff 100644
--- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
+++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
@@ -1,8 +1,8 @@
 error[E0720]: cannot resolve opaque type
-  --> $DIR/infinite-cycle-involving-weak.rs:3:10
+  --> $DIR/infinite-cycle-involving-weak.rs:6:13
    |
-LL | type T = impl Copy;
-   |          ^^^^^^^^^ cannot resolve opaque type
+LL | fn foo() -> T {
+   |             ^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/crashes/139817.rs b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs
index d439ed4cacb..f4e2cb0c037 100644
--- a/tests/crashes/139817.rs
+++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs
@@ -1,8 +1,12 @@
-//@ known-bug: #139817
+#![feature(type_alias_impl_trait)]
+
 fn enum_upvar() {
     type T = impl Copy;
     let foo: T = Some((42, std::marker::PhantomData::<T>));
     let x = move || match foo {
         None => (),
+        //~^ ERROR cannot resolve opaque type
     };
 }
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr
new file mode 100644
index 00000000000..2bfce2d63a8
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr
@@ -0,0 +1,9 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/match-upvar-discriminant-of-opaque.rs:7:9
+   |
+LL |         None => (),
+   |         ^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
index 94597adfed0..fe354cc6545 100644
--- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
@@ -13,7 +13,7 @@ pub fn add(
     n: Diff,
     m: Diff,
 ) -> Diff {
-    //~^ ERROR concrete type differs
+    //~^ ERROR cannot resolve opaque type
     move |x: usize| m(n(x))
 }
 
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
index 59ff9917612..847f1cc6c2e 100644
--- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-fn-tait.rs:15:6
    |
 LL | ) -> Diff {
-   |      ^^^^ expected `{closure@$DIR/recursive-fn-tait.rs:8:5: 8:16}`, got `{closure@$DIR/recursive-fn-tait.rs:17:5: 17:20}`
-   |
-note: previous use here
-  --> $DIR/recursive-fn-tait.rs:7:18
-   |
-LL | pub fn lift() -> Diff {
-   |                  ^^^^
+   |      ^^^^
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
index 858f2a2feb6..7803b3b78db 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
@@ -13,7 +13,7 @@ fn transform<S>() -> impl std::fmt::Display {
 }
 #[define_opaque(Op)]
 fn bad() -> Op {
-    //~^ ERROR concrete type differs from previous defining opaque type use
+    //~^ ERROR cannot resolve opaque type
     transform::<Op>()
 }
 
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
index e527b5bc7f8..837df7f5d43 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-tait-conflicting-defn-2.rs:15:13
    |
 LL | fn bad() -> Op {
-   |             ^^ expected `&&str`, got `impl std::fmt::Display`
-   |
-note: previous use here
-  --> $DIR/recursive-tait-conflicting-defn-2.rs:7:13
-   |
-LL | fn foo() -> Op {
    |             ^^
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
index 90581a98a34..d66ceda5234 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
@@ -23,7 +23,7 @@ pub fn test() -> TestImpl {
 
 #[define_opaque(TestImpl)]
 fn make_option2() -> Option<TestImpl> {
-    //~^ ERROR concrete type differs from previous defining opaque type use
+    //~^ ERROR cannot resolve opaque type
     let inner = make_option().unwrap();
     Some(B { inner })
 }
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
index 256f13b6221..c7a3381d615 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-tait-conflicting-defn.rs:25:22
    |
 LL | fn make_option2() -> Option<TestImpl> {
-   |                      ^^^^^^^^^^^^^^^^ expected `A`, got `B<TestImpl>`
-   |
-note: previous use here
-  --> $DIR/recursive-tait-conflicting-defn.rs:20:18
-   |
-LL | pub fn test() -> TestImpl {
-   |                  ^^^^^^^^
+   |                      ^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs b/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs
new file mode 100644
index 00000000000..589a90e71d6
--- /dev/null
+++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.rs
@@ -0,0 +1,10 @@
+fn main() {
+    b"abc".iter().for_each(|x| x); //~ ERROR: mismatched types
+
+    b"abc".iter().for_each(|x| dbg!(x)); //~ ERROR: mismatched types
+
+    b"abc".iter().for_each(|x| {
+        println!("{}", x);
+        x //~ ERROR: mismatched types
+    })
+}
diff --git a/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr
new file mode 100644
index 00000000000..31acc5bb10e
--- /dev/null
+++ b/tests/ui/typeck/closure-ty-mismatch-issue-128561.stderr
@@ -0,0 +1,28 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-ty-mismatch-issue-128561.rs:2:32
+   |
+LL |     b"abc".iter().for_each(|x| x);
+   |                                ^ expected `()`, found `&u8`
+   |
+help: consider ignoring the value
+   |
+LL |     b"abc".iter().for_each(|x| _ = x);
+   |                                +++
+
+error[E0308]: mismatched types
+  --> $DIR/closure-ty-mismatch-issue-128561.rs:4:32
+   |
+LL |     b"abc".iter().for_each(|x| dbg!(x));
+   |                                ^^^^^^^ expected `()`, found `&u8`
+   |
+   = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/closure-ty-mismatch-issue-128561.rs:8:9
+   |
+LL |         x
+   |         ^ expected `()`, found `&u8`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr
index 8a4d767c143..e5050b4d316 100644
--- a/tests/ui/typeck/ice-unexpected-region-123863.stderr
+++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr
@@ -39,7 +39,7 @@ LL |     Inner::concat_strs::<"a">::A
 help: if there were a trait named `Example` with associated type `concat_strs` implemented for `Inner<_>`, you could use the fully-qualified path
    |
 LL -     Inner::concat_strs::<"a">::A
-LL +     <Inner<_> as Example>::concat_strs::A
+LL +     <Inner<_> as Example>::concat_strs::<"a">::A
    |
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr
index 289c8d161ae..157ba5a1672 100644
--- a/tests/ui/typeck/issue-107087.stderr
+++ b/tests/ui/typeck/issue-107087.stderr
@@ -2,7 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-107087.rs:16:5
    |
 LL |     A::B::<>::C
-   |     ^^^^^^^^ help: use fully-qualified syntax: `<A<_> as Foo>::B`
+   |     ^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL -     A::B::<>::C
+LL +     <A<_> as Foo>::B::<>::C
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unsafe-binders/non-strucutral-type-diag.rs b/tests/ui/unsafe-binders/non-strucutral-type-diag.rs
new file mode 100644
index 00000000000..e021e9567e5
--- /dev/null
+++ b/tests/ui/unsafe-binders/non-strucutral-type-diag.rs
@@ -0,0 +1,17 @@
+// regression test for <https://github.com/rust-lang/rust/issues/141422>.
+
+#![feature(unsafe_binders)]
+#![allow(incomplete_features)]
+
+#[derive(Copy, Clone)]
+struct Adt<'a>(&'a ());
+
+const C: Option<(unsafe<'a> Adt<'a>, Box<dyn Send>)> = None;
+
+fn main() {
+    match None {
+        C => {}
+        //~^ ERROR constant of non-structural type
+        _ => {}
+    }
+}
diff --git a/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr b/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr
new file mode 100644
index 00000000000..ab23210b2e5
--- /dev/null
+++ b/tests/ui/unsafe-binders/non-strucutral-type-diag.stderr
@@ -0,0 +1,13 @@
+error: constant of non-structural type `Option<(unsafe<'a> Adt<'a>, Box<dyn Send>)>` in a pattern
+  --> $DIR/non-strucutral-type-diag.rs:13:9
+   |
+LL | const C: Option<(unsafe<'a> Adt<'a>, Box<dyn Send>)> = None;
+   | ---------------------------------------------------- constant defined here
+...
+LL |         C => {}
+   |         ^ constant of non-structural type
+   |
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+
+error: aborting due to 1 previous error
+
diff --git a/triagebot.toml b/triagebot.toml
index 3afa2d36410..9d7a0ef5aec 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -44,8 +44,6 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
-[glacier]
-
 [ping.icebreakers-llvm]
 message = """\
 Hey LLVM ICE-breakers! This bug has been identified as a good
@@ -887,6 +885,7 @@ message = "Some changes occurred in HTML/CSS/JS."
 cc = [
     "@GuillaumeGomez",
     "@jsha",
+    "@lolbinarycat",
 ]
 
 [mentions."tests/rustdoc-gui/"]
@@ -1171,7 +1170,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
     "fmease",
     "jyn514",
-    "Noratrieb",
     "spastorino",
 ]
 
@@ -1198,7 +1196,6 @@ compiler = [
     "@lcnr",
     "@Nadrieril",
     "@nnethercote",
-    "@Noratrieb",
     "@oli-obk",
     "@petrochenkov",
     "@SparrowLii",
@@ -1206,7 +1203,6 @@ compiler = [
 ]
 libs = [
     "@Mark-Simulacrum",
-    "@Noratrieb",
     "@workingjubilee",
     "@joboet",
     "@jhpratt",
@@ -1427,3 +1423,12 @@ compiletest = [
 
 [behind-upstream]
 days-threshold = 14
+
+# Canonicalize issue numbers to avoid closing the wrong issue
+# when commits are included in subtrees, as well as warning links in commits.
+# Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html
+[issue-links]
+
+# Prevents mentions in commits to avoid users being spammed
+# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html
+[no-mentions]