about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Cargo.lock156
-rw-r--r--src/bootstrap/Cargo.toml4
-rw-r--r--src/bootstrap/defaults/bootstrap.compiler.toml2
-rw-r--r--src/bootstrap/src/bin/main.rs4
-rw-r--r--src/bootstrap/src/bin/rustc.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs67
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs12
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs81
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs17
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs6
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs9
-rw-r--r--src/bootstrap/src/core/builder/mod.rs14
-rw-r--r--src/bootstrap/src/core/config/config.rs49
-rw-r--r--src/bootstrap/src/core/download.rs13
-rw-r--r--src/bootstrap/src/core/sanity.rs25
-rw-r--r--src/bootstrap/src/lib.rs6
-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.rs1
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs12
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/helpers.rs36
-rw-r--r--src/bootstrap/src/utils/job.rs1
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs4
-rwxr-xr-xsrc/ci/cpu-usage-over-time.py2
-rw-r--r--src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile (renamed from src/ci/docker/host-x86_64/dist-ohos/Dockerfile)18
-rw-r--r--src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile53
-rw-r--r--src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile53
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh8
-rw-r--r--src/ci/github-actions/jobs.yml20
-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/.github/workflows/ci.yml2
-rw-r--r--src/doc/rustc-dev-guide/README.md10
-rw-r--r--src/doc/rustc-dev-guide/ci/date-check/Cargo.lock207
-rw-r--r--src/doc/rustc-dev-guide/ci/date-check/Cargo.toml6
-rw-r--r--src/doc/rustc-dev-guide/ci/date-check/src/main.rs2
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/Cargo.lock2
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/Cargo.toml3
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/src/main.rs6
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/src/sync.rs42
-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/autodiff/installation.md2
-rw-r--r--src/doc/rustc-dev-guide/src/bug-fix-procedure.md36
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md4
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md4
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-src.md33
-rw-r--r--src/doc/rustc-dev-guide/src/guides/editions.md54
-rw-r--r--src/doc/rustc-dev-guide/src/macro-expansion.md6
-rw-r--r--src/doc/rustc-dev-guide/src/mir/dataflow.md3
-rw-r--r--src/doc/rustc-dev-guide/src/normalization.md309
-rw-r--r--src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md4
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc-internals.md4
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md8
-rw-r--r--src/doc/rustc-dev-guide/src/serialization.md2
-rw-r--r--src/doc/rustc-dev-guide/src/solve/normalization.md127
-rw-r--r--src/doc/rustc-dev-guide/src/solve/significant-changes.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/best-practices.md6
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ci.md16
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md8
-rw-r--r--src/doc/rustc-dev-guide/src/tests/intro.md9
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ui.md6
-rw-r--r--src/doc/rustc-dev-guide/src/traits/unsize.md12
-rw-r--r--src/doc/rustc-dev-guide/src/ty-fold.md56
-rw-r--r--src/doc/rustc-dev-guide/src/type-checking.md2
-rw-r--r--src/doc/rustc-dev-guide/src/type-inference.md2
-rw-r--r--src/doc/rustc-dev-guide/src/typing_parameter_envs.md8
-rw-r--r--src/doc/rustc-dev-guide/triagebot.toml3
-rw-r--r--src/doc/rustc/book.toml2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md29
-rw-r--r--src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md1
-rw-r--r--src/doc/rustc/src/platform-support/xtensa.md2
-rw-r--r--src/doc/rustc/theme/pagetoc.css84
-rw-r--r--src/doc/rustc/theme/pagetoc.js104
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md2
-rw-r--r--src/doc/style-guide/src/editions.md4
-rw-r--r--src/doc/style-guide/src/expressions.md9
-rw-r--r--src/doc/style-guide/src/nightly.md12
-rw-r--r--src/doc/style-guide/src/types.md12
-rw-r--r--src/doc/unstable-book/src/language-features/arbitrary-self-types.md2
-rw-r--r--src/doc/unstable-book/src/language-features/deref-patterns.md34
-rw-r--r--src/doc/unstable-book/src/language-features/f128.md2
-rw-r--r--src/doc/unstable-book/src/language-features/f16.md2
-rw-r--r--src/doc/unstable-book/src/language-features/frontmatter.md25
-rw-r--r--src/doc/unstable-book/src/library-features/duration-constructors-lite.md11
-rw-r--r--src/doc/unstable-book/src/library-features/duration-constructors.md3
-rw-r--r--src/etc/test-float-parse/Cargo.toml7
-rw-r--r--src/etc/test-float-parse/src/gen_/subnorm.rs9
-rw-r--r--src/etc/test-float-parse/src/lib.rs7
-rw-r--r--src/etc/test-float-parse/src/traits.rs5
m---------src/gcc0
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/cfg.rs64
-rw-r--r--src/librustdoc/clean/mod.rs22
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs2
-rw-r--r--src/librustdoc/clean/types.rs40
-rw-r--r--src/librustdoc/config.rs6
-rw-r--r--src/librustdoc/doctest.rs67
-rw-r--r--src/librustdoc/doctest/make.rs65
-rw-r--r--src/librustdoc/doctest/markdown.rs1
-rw-r--r--src/librustdoc/doctest/tests.rs22
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/formats/item_type.rs33
-rw-r--r--src/librustdoc/html/format.rs83
-rw-r--r--src/librustdoc/html/highlight.rs6
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/static/css/noscript.css2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css95
-rw-r--r--src/librustdoc/html/templates/page.html2
-rw-r--r--src/librustdoc/json/conversions.rs6
-rw-r--r--src/librustdoc/lib.rs53
-rw-r--r--src/librustdoc/lint.rs10
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs21
-rw-r--r--src/librustdoc/passes/lint.rs4
-rw-r--r--src/librustdoc/passes/lint/unportable_markdown.rs145
-rw-r--r--src/librustdoc/passes/propagate_stability.rs2
m---------src/llvm-project0
-rw-r--r--src/stage0920
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/clippy_changelog.yml17
-rw-r--r--src/tools/clippy/CHANGELOG.md104
-rw-r--r--src/tools/clippy/CONTRIBUTING.md2
-rw-r--r--src/tools/clippy/Cargo.toml5
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md2
-rw-r--r--src/tools/clippy/book/src/development/basics.md28
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md4
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/changelog_update.md27
-rw-r--r--src/tools/clippy/book/src/development/trait_checking.md16
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md21
-rw-r--r--src/tools/clippy/clippy.toml3
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs7
-rw-r--r--src/tools/clippy/clippy_config/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/types.rs95
-rw-r--r--src/tools/clippy/clippy_dev/src/deprecate_lint.rs174
-rw-r--r--src/tools/clippy/clippy_dev/src/dogfood.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs32
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs37
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs165
-rw-r--r--src/tools/clippy/clippy_dev/src/release.rs32
-rw-r--r--src/tools/clippy/clippy_dev/src/rename_lint.rs194
-rw-r--r--src/tools/clippy/clippy_dev/src/sync.rs31
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs1110
-rw-r--r--src/tools/clippy/clippy_dev/src/utils.rs650
-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/assigning_clones.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs3
-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_ptr_alignment.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-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/equatable_if_let.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_abs_diff.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_div_ceil.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs71
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/io_other_error.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/return_and_then.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_split.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/integer_division.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/single_option_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs105
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs155
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs130
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs5
-rw-r--r--src/tools/clippy/clippy_lints_internal/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs6
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs164
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/internal_paths.rs17
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/interning_literals.rs102
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs108
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lib.rs20
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs9
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs7
-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/symbols.rs207
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs317
-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/higher.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs323
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs391
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs135
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs89
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs23
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs1
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/src/driver.rs1
-rw-r--r--src/tools/clippy/tests/compile-test.rs2
-rw-r--r--src/tools/clippy/tests/dogfood.rs16
-rw-r--r--src/tools/clippy/tests/integration.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/auxiliary/paths.rs4
-rw-r--r--src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.rs60
-rw-r--r--src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.stderr23
-rw-r--r--src/tools/clippy/tests/ui-internal/interning_literals.stderr15
-rw-r--r--src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr9
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.rs30
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.stderr26
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.fixed28
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.rs28
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str.stderr97
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs15
-rw-r--r--src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr43
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed77
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs85
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr120
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs19
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr31
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed1
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs13
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr11
-rw-r--r--src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs26
-rw-r--r--src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr38
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml3
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs8
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr42
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr8
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml9
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs5
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr27
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml4
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs5
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr8
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unloaded_crate/clippy.toml10
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr20
-rw-r--r--src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr2
-rw-r--r--src/tools/clippy/tests/ui/author.stdout2
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout10
-rw-r--r--src/tools/clippy/tests/ui/author/call.stdout3
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.stdout5
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout8
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout11
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout11
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout6
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout9
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs79
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macros.rs1
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.fixed1
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.rs1
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.stderr6
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.fixed1
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.rs1
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.stderr22
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs85
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr88
-rw-r--r--src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.fixed64
-rw-r--r--src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.rs64
-rw-r--r--src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.stderr23
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.fixed30
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.rs30
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.stderr8
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.fixed68
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.stderr132
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed29
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if_let_chains.rs52
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr58
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs1
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr52
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed1
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs1
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr26
-rw-r--r--src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.fixed14
-rw-r--r--src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.rs14
-rw-r--r--src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.stderr100
-rw-r--r--src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.fixed13
-rw-r--r--src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.stderr17
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.fixed15
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.rs15
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.stderr4
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs15
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr4
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs15
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.fixed36
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.rs36
-rw-r--r--src/tools/clippy/tests/ui/equatable_if_let.stderr20
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed2
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs2
-rw-r--r--src/tools/clippy/tests/ui/integer_division.rs8
-rw-r--r--src/tools/clippy/tests/ui/integer_division.stderr16
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.rs1
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.stderr20
-rw-r--r--src/tools/clippy/tests/ui/let_with_type_underscore.fixed47
-rw-r--r--src/tools/clippy/tests/ui/let_with_type_underscore.stderr34
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.fixed23
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.rs23
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.stderr62
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs32
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.stderr22
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr48
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_fill.fixed37
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_fill.rs37
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed13
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.rs13
-rw-r--r--src/tools/clippy/tests/ui/needless_if.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_if.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_if.stderr14
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.fixed6
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.rs6
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr34
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr148
-rw-r--r--src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed7
-rw-r--r--src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs7
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.fixed28
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.rs18
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq.stderr38
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.fixed20
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.rs12
-rw-r--r--src/tools/clippy/tests/ui/ptr_eq_no_std.stderr26
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed5
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs5
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr20
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed5
-rw-r--r--src/tools/clippy/tests/ui/rename.rs5
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr164
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.fixed52
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.rs47
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.stderr61
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.fixed17
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.rs17
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.stderr14
-rw-r--r--src/tools/clippy/tests/ui/transmute.rs132
-rw-r--r--src/tools/clippy/tests/ui/transmute.stderr230
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.fixed60
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.rs60
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.stderr89
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char.fixed16
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char.rs16
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char.stderr17
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed28
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs28
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr17
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.rs27
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr30
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed16
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs8
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.fixed146
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.stderr128
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.fixed146
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.stderr122
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.fixed21
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs26
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.stderr32
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs17
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.stderr34
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr10
-rw-r--r--src/tools/clippy/tests/ui/zombie_processes.rs22
-rw-r--r--src/tools/clippy/triagebot.toml6
-rwxr-xr-xsrc/tools/clippy/util/etc/pre-commit.sh1
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/errors.rs3
-rw-r--r--src/tools/compiletest/src/json.rs55
-rw-r--r--src/tools/compiletest/src/runtest.rs68
-rw-r--r--src/tools/compiletest/src/runtest/incremental.rs14
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs47
-rw-r--r--src/tools/coverage-dump/Cargo.toml3
-rw-r--r--src/tools/coverage-dump/src/covfun.rs86
-rw-r--r--src/tools/coverage-dump/src/covfun/tests.rs53
-rw-r--r--src/tools/coverage-dump/src/covmap.rs75
-rw-r--r--src/tools/coverage-dump/src/llvm_utils.rs85
-rw-r--r--src/tools/coverage-dump/src/llvm_utils/tests.rs (renamed from src/tools/coverage-dump/src/parser/tests.rs)4
-rw-r--r--src/tools/coverage-dump/src/main.rs5
-rw-r--r--src/tools/coverage-dump/src/parser.rs34
-rw-r--r--src/tools/coverage-dump/src/prf_names.rs40
-rw-r--r--src/tools/features-status-dump/Cargo.toml2
-rw-r--r--src/tools/lint-docs/src/lib.rs1
-rw-r--r--src/tools/miri/.gitignore5
-rw-r--r--src/tools/miri/CONTRIBUTING.md10
-rw-r--r--src/tools/miri/Cargo.toml3
-rw-r--r--src/tools/miri/README.md59
-rw-r--r--src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs5
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/main.rs34
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs14
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs8
-rw-r--r--src/tools/miri/miri-script/Cargo.toml2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs89
-rw-r--r--src/tools/miri/miri-script/src/main.rs9
-rw-r--r--src/tools/miri/miri-script/src/util.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs17
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs15
-rw-r--r--src/tools/miri/src/bin/miri.rs79
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs5
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs112
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs111
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs10
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs256
-rw-r--r--src/tools/miri/src/concurrency/data_race_handler.rs91
-rw-r--r--src/tools/miri/src/concurrency/genmc/config.rs19
-rw-r--r--src/tools/miri/src/concurrency/genmc/dummy.rs239
-rw-r--r--src/tools/miri/src/concurrency/genmc/mod.rs284
-rw-r--r--src/tools/miri/src/concurrency/init_once.rs4
-rw-r--r--src/tools/miri/src/concurrency/mod.rs16
-rw-r--r--src/tools/miri/src/concurrency/sync.rs23
-rw-r--r--src/tools/miri/src/concurrency/thread.rs236
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs10
-rw-r--r--src/tools/miri/src/concurrency/weak_memory.rs34
-rw-r--r--src/tools/miri/src/diagnostics.rs12
-rw-r--r--src/tools/miri/src/eval.rs99
-rw-r--r--src/tools/miri/src/helpers.rs13
-rw-r--r--src/tools/miri/src/intrinsics/atomic.rs31
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs10
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs13
-rw-r--r--src/tools/miri/src/lib.rs4
-rw-r--r--src/tools/miri/src/machine.rs176
-rw-r--r--src/tools/miri/src/shims/native_lib.rs15
-rw-r--r--src/tools/miri/src/shims/panic.rs1
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs2
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs4
-rwxr-xr-xsrc/tools/miri/test-cargo-miri/run-test.py17
-rw-r--r--src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref12
-rw-r--r--src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref10
-rw-r--r--src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref (renamed from src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref)0
-rw-r--r--src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref11
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memchr_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler.rs2
-rw-r--r--src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs2
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr4
-rw-r--r--src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr4
-rw-r--r--src/tools/miri/tests/fail/data_race/alloc_read_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/alloc_write_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dangling_thread_race.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/fence_after_load.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs2
-rw-r--r--src/tools/miri/tests/fail/data_race/local_variable_read_race.rs2
-rw-r--r--src/tools/miri/tests/fail/data_race/local_variable_write_race.rs2
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/read_write_race.rs4
-rw-r--r--src/tools/miri/tests/fail/data_race/read_write_race_stack.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/relax_acquire_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/release_seq_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/rmw_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/stack_pop_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/write_write_race.rs6
-rw-r--r--src/tools/miri/tests/fail/data_race/write_write_race_stack.rs5
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_arg_abi.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs6
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr2
-rw-r--r--src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs2
-rw-r--r--src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-gather.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-gather.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-scatter.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/abort_unwind.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/abort_unwind.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/double_panic.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/double_panic.stderr2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort1.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort1.stderr8
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort2.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort2.stderr8
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort3.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort3.stderr8
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort4.rs2
-rw-r--r--src/tools/miri/tests/fail/panic/panic_abort4.stderr8
-rw-r--r--src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/provenance_transmute.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid.stderr4
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr4
-rw-r--r--src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs2
-rw-r--r--src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr2
-rw-r--r--src/tools/miri/tests/fail/rc_as_ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/reading_half_a_pointer.stderr4
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs2
-rw-r--r--src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr4
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs3
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs3
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr4
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.rs2
-rw-r--r--src/tools/miri/tests/fail/terminate-terminator.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr15
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs58
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr31
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs10
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/spurious_read.rs6
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/unique.rs27
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr38
-rw-r--r--src/tools/miri/tests/fail/unwind-action-terminate.rs2
-rw-r--r--src/tools/miri/tests/fail/unwind-action-terminate.stderr2
-rw-r--r--src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr22
-rw-r--r--src/tools/miri/tests/fail/weak_memory/weak_uninit.rs2
-rw-r--r--src/tools/miri/tests/fail/zst_local_oob.rs2
-rw-r--r--src/tools/miri/tests/fail/zst_local_oob.stderr4
-rw-r--r--src/tools/miri/tests/many-seeds/reentrant-lock.rs19
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-pipe.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/pthread-sync.rs2
-rw-r--r--src/tools/miri/tests/pass/both_borrows/2phase.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/2phase.rs)46
-rw-r--r--src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs)31
-rw-r--r--src/tools/miri/tests/pass/both_borrows/interior_mutability.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs)38
-rw-r--r--src/tools/miri/tests/pass/concurrency/data_race.rs3
-rw-r--r--src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync.rs2
-rw-r--r--src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs2
-rw-r--r--src/tools/miri/tests/pass/coroutine.rs8
-rw-r--r--src/tools/miri/tests/pass/intrinsics/intrinsics.rs26
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs13
-rw-r--r--src/tools/miri/tests/pass/panic/concurrent-panic.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/env/var.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs1
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr1
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr (renamed from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr)4
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/no_field_retagging.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/non_scalar_field_retagging.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/non_scalar_field_retagging.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/stack-printing.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout (renamed from src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/stacked-borrows.rs50
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs)0
-rw-r--r--src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs)0
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs27
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs8
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr8
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs35
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr (renamed from src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr)7
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs178
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reserved.rs18
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/spurious_read.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs259
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/unique.default.stderr21
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/unique.rs67
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr24
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/vec_unique.rs69
-rw-r--r--src/tools/miri/tests/pass/vec.rs3
-rw-r--r--src/tools/miri/tests/pass/vecdeque.rs4
-rw-r--r--src/tools/miri/tests/pass/weak_memory/weak.rs2
-rw-r--r--src/tools/miri/tests/ui.rs13
-rw-r--r--src/tools/opt-dist/Cargo.toml5
-rw-r--r--src/tools/opt-dist/src/bolt.rs2
-rw-r--r--src/tools/opt-dist/src/environment.rs5
-rw-r--r--src/tools/opt-dist/src/exec.rs11
-rw-r--r--src/tools/opt-dist/src/main.rs26
-rw-r--r--src/tools/run-make-support/src/command.rs6
-rw-r--r--src/tools/run-make-support/src/external_deps/cargo.rs5
-rw-r--r--src/tools/run-make-support/src/external_deps/rustdoc.rs4
-rw-r--r--src/tools/run-make-support/src/macros.rs12
-rw-r--r--src/tools/rust-analyzer/Cargo.lock28
-rw-r--r--src/tools/rust-analyzer/Cargo.toml15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs4
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/grammar.rs1
-rw-r--r--src/tools/rustbook/Cargo.lock333
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustdoc-gui-test/src/config.rs17
-rw-r--r--src/tools/rustfmt/src/items.rs5
-rw-r--r--src/tools/rustfmt/src/parse/macros/asm.rs4
-rw-r--r--src/tools/tidy/src/deps.rs13
-rw-r--r--src/tools/tidy/src/issues.txt71
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/version2
819 files changed, 12309 insertions, 9039 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index d415668f54a..d10d2d9bf8c 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -159,12 +159,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
 name = "cpufeatures"
 version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -226,9 +220,9 @@ dependencies = [
 
 [[package]]
 name = "errno"
-version = "0.3.10"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -242,13 +236,13 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "fd-lock"
-version = "4.0.2"
+version = "4.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
+checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
 dependencies = [
  "cfg-if",
- "rustix 0.38.40",
- "windows-sys 0.52.0",
+ "rustix",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -353,9 +347,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.171"
+version = "0.2.172"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "libredox"
@@ -370,12 +364,6 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
-
-[[package]]
-name = "linux-raw-sys"
 version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
@@ -441,6 +429,25 @@ dependencies = [
 ]
 
 [[package]]
+name = "objc2-core-foundation"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "objc2-io-kit"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
+dependencies = [
+ "libc",
+ "objc2-core-foundation",
+]
+
+[[package]]
 name = "object"
 version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -572,27 +579,14 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "rustix"
-version = "0.38.40"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
 dependencies = [
  "bitflags",
  "errno",
  "libc",
- "linux-raw-sys 0.4.14",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "rustix"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys 0.9.3",
+ "linux-raw-sys",
  "windows-sys 0.59.0",
 ]
 
@@ -700,14 +694,15 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.33.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46"
+checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
 dependencies = [
- "core-foundation-sys",
  "libc",
  "memchr",
  "ntapi",
+ "objc2-core-foundation",
+ "objc2-io-kit",
  "windows",
 ]
 
@@ -731,7 +726,7 @@ dependencies = [
  "fastrand",
  "getrandom",
  "once_cell",
- "rustix 1.0.2",
+ "rustix",
  "windows-sys 0.59.0",
 ]
 
@@ -923,31 +918,54 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows"
-version = "0.57.0"
+version = "0.61.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
+dependencies = [
+ "windows-collections",
+ "windows-core",
+ "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",
- "windows-targets",
 ]
 
 [[package]]
 name = "windows-core"
-version = "0.57.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
  "windows-implement",
  "windows-interface",
+ "windows-link",
  "windows-result",
- "windows-targets",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
+dependencies = [
+ "windows-core",
+ "windows-link",
 ]
 
 [[package]]
 name = "windows-implement"
-version = "0.57.0"
+version = "0.60.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -956,9 +974,9 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.57.0"
+version = "0.59.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -966,12 +984,37 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-link"
+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 = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
+dependencies = [
+ "windows-core",
+ "windows-link",
+]
+
+[[package]]
 name = "windows-result"
-version = "0.1.2"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
 dependencies = [
- "windows-targets",
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
 ]
 
 [[package]]
@@ -1067,13 +1110,12 @@ dependencies = [
 
 [[package]]
 name = "xattr"
-version = "1.3.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
+checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
 dependencies = [
  "libc",
- "linux-raw-sys 0.4.14",
- "rustix 0.38.40",
+ "rustix",
 ]
 
 [[package]]
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 712a9b04c1a..9652d18f1a6 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -58,7 +58,7 @@ walkdir = "2.4"
 xz2 = "0.1"
 
 # Dependencies needed by the build-metrics feature
-sysinfo = { version = "0.33.0", default-features = false, optional = true, features = ["system"] }
+sysinfo = { version = "0.35.0", default-features = false, optional = true, features = ["system"] }
 
 # Dependencies needed by the `tracing` feature
 tracing = { version = "0.1", optional = true, features = ["attributes"] }
@@ -70,7 +70,7 @@ tracing-tree = { version = "0.4.0", optional = true }
 version = "1.0.0"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.57"
+version = "0.61"
 features = [
     "Win32_Foundation",
     "Win32_Security",
diff --git a/src/bootstrap/defaults/bootstrap.compiler.toml b/src/bootstrap/defaults/bootstrap.compiler.toml
index 269b90106e3..9dcb20ed483 100644
--- a/src/bootstrap/defaults/bootstrap.compiler.toml
+++ b/src/bootstrap/defaults/bootstrap.compiler.toml
@@ -30,8 +30,6 @@ download-rustc = false
 # Having this set to true disrupts compiler development workflows for people who use `llvm.download-ci-llvm = true`
 # because we don't provide ci-llvm on the `rustc-alt-builds` server. Therefore, it is kept off by default.
 assertions = false
-# Enable warnings during the LLVM compilation (when LLVM is changed, causing a compilation)
-enable-warnings = true
 # Will download LLVM from CI if available on your platform.
 # If you intend to modify `src/llvm-project`, use `"if-unchanged"` or `false` instead.
 download-ci-llvm = true
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index cbfe00a757c..833f8027951 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -163,7 +163,7 @@ fn check_version(config: &Config) -> Option<String> {
             msg.push_str("WARNING: The `change-id` is missing in the `bootstrap.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n");
             msg.push_str("NOTE: to silence this warning, ");
             msg.push_str(&format!(
-                "add `change-id = {latest_change_id}` or change-id = \"ignore\" at the top of `bootstrap.toml`"
+                "add `change-id = {latest_change_id}` or `change-id = \"ignore\"` at the top of `bootstrap.toml`"
             ));
             return Some(msg);
         }
@@ -195,7 +195,7 @@ fn check_version(config: &Config) -> Option<String> {
 
     msg.push_str("NOTE: to silence this warning, ");
     msg.push_str(&format!(
-        "update `bootstrap.toml` to use `change-id = {latest_change_id}` or change-id = \"ignore\" instead"
+        "update `bootstrap.toml` to use `change-id = {latest_change_id}` or `change-id = \"ignore\"` instead"
     ));
 
     if io::stdout().is_terminal() {
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index d8cae02456c..374884d8a9a 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -58,8 +58,8 @@ fn main() {
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
     let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);
 
-    let rustc_real = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
-    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
+    let rustc_real = env::var_os(rustc).unwrap_or_else(|| panic!("{rustc:?} was not set"));
+    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{libdir:?} was not set"));
     let mut dylib_path = dylib_path();
     dylib_path.insert(0, PathBuf::from(&libdir));
 
@@ -342,7 +342,7 @@ fn format_rusage_data(child: Child) -> Option<String> {
     use windows::Win32::System::Threading::GetProcessTimes;
     use windows::Win32::System::Time::FileTimeToSystemTime;
 
-    let handle = HANDLE(child.as_raw_handle() as isize);
+    let handle = HANDLE(child.as_raw_handle());
 
     let mut user_filetime = Default::default();
     let mut user_time = Default::default();
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index ae9511b7867..fa848c492b4 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -527,3 +527,70 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
 // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
 // check to make it easier to work on.
 tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
+
+/// Check step for the `coverage-dump` bootstrap tool. The coverage-dump tool
+/// is used internally by coverage tests.
+///
+/// FIXME(Zalathar): This is temporarily separate from the other tool check
+/// steps so that it can use the stage 0 compiler instead of `top_stage`,
+/// without introducing conflicts with the stage 0 redesign (#119899).
+///
+/// After the stage 0 redesign lands, we can look into using the stage 0
+/// compiler to check all bootstrap tools (#139170).
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub(crate) struct CoverageDump;
+
+impl CoverageDump {
+    const PATH: &str = "src/tools/coverage-dump";
+}
+
+impl Step for CoverageDump {
+    type Output = ();
+
+    /// Most contributors won't care about coverage-dump, so don't make their
+    /// check builds slower unless they opt in and check it explicitly.
+    const DEFAULT: bool = false;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path(Self::PATH)
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Self {});
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        // Make sure we haven't forgotten any fields, if there are any.
+        let Self {} = self;
+        let display_name = "coverage-dump";
+        let host = builder.config.build;
+        let target = host;
+        let mode = Mode::ToolBootstrap;
+
+        let compiler = builder.compiler(0, host);
+        let cargo = prepare_tool_cargo(
+            builder,
+            compiler,
+            mode,
+            target,
+            builder.kind,
+            Self::PATH,
+            SourceType::InTree,
+            &[],
+        );
+
+        let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target))
+            .with_prefix(&format!("{display_name}-check"));
+
+        let _guard = builder.msg_tool(
+            builder.kind,
+            mode,
+            display_name,
+            compiler.stage,
+            &compiler.host,
+            &target,
+        );
+        run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 21e9fea9363..882fcd08780 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -129,7 +129,7 @@ fn clean_specific_stage(build: &Build, stage: u32) {
 
         for entry in entries {
             let entry = t!(entry);
-            let stage_prefix = format!("stage{}", stage);
+            let stage_prefix = format!("stage{stage}");
 
             // if current entry is not related with the target stage, continue
             if !entry.file_name().to_str().unwrap_or("").contains(&stage_prefix) {
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index d3ab215d1b5..07fd51919d4 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -59,7 +59,7 @@ fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str])
     let all_args = std::env::args().collect::<Vec<_>>();
     args.extend(get_clippy_rules_in_order(&all_args, config));
 
-    args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{}", lint)));
+    args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{lint}")));
     args.extend(builder.config.free_args.clone());
     args
 }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 2e5865e5096..67daf81ee54 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1771,7 +1771,7 @@ impl Step for Sysroot {
             } else if builder.download_rustc() && compiler.stage != builder.top_stage {
                 host_dir.join("ci-rustc-sysroot")
             } else {
-                host_dir.join(format!("stage{}", stage))
+                host_dir.join(format!("stage{stage}"))
             }
         };
         let sysroot = sysroot_dir(compiler.stage);
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 3c412683b94..aa2c7509c2a 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1403,14 +1403,14 @@ impl Step for CodegenBackend {
         let backend = self.backend;
 
         let mut tarball =
-            Tarball::new(builder, &format!("rustc-codegen-{}", backend), &compiler.host.triple);
+            Tarball::new(builder, &format!("rustc-codegen-{backend}"), &compiler.host.triple);
         if backend == "cranelift" {
             tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
         } else {
-            panic!("Unknown backend rustc_codegen_{}", backend);
+            panic!("Unknown backend rustc_codegen_{backend}");
         }
         tarball.is_preview(true);
-        tarball.add_legal_and_readme_to(format!("share/doc/rustc_codegen_{}", backend));
+        tarball.add_legal_and_readme_to(format!("share/doc/rustc_codegen_{backend}"));
 
         let src = builder.sysroot(compiler);
         let backends_src = builder.sysroot_codegen_backends(compiler);
@@ -1422,7 +1422,7 @@ impl Step for CodegenBackend {
         // Don't use custom libdir here because ^lib/ will be resolved again with installer
         let backends_dst = PathBuf::from("lib").join(backends_rel);
 
-        let backend_name = format!("rustc_codegen_{}", backend);
+        let backend_name = format!("rustc_codegen_{backend}");
         let mut found_backend = false;
         for backend in fs::read_dir(&backends_src).unwrap() {
             let file_name = backend.unwrap().file_name();
@@ -1623,7 +1623,7 @@ impl Step for Extended {
             let pkgbuild = |component: &str| {
                 let mut cmd = command("pkgbuild");
                 cmd.arg("--identifier")
-                    .arg(format!("org.rust-lang.{}", component))
+                    .arg(format!("org.rust-lang.{component}"))
                     .arg("--scripts")
                     .arg(pkg.join(component))
                     .arg("--nopayload")
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 9da8b27a917..1c317ce4b86 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -9,7 +9,7 @@ use std::sync::mpsc::SyncSender;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 
-use crate::core::builder::Builder;
+use crate::core::builder::{Builder, Kind};
 use crate::utils::build_stamp::BuildStamp;
 use crate::utils::exec::command;
 use crate::utils::helpers::{self, t};
@@ -58,7 +58,7 @@ fn rustfmt(
 fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> {
     let stamp_file = BuildStamp::new(&build.out).with_prefix("rustfmt");
 
-    let mut cmd = command(build.initial_rustfmt()?);
+    let mut cmd = command(build.config.initial_rustfmt.as_ref()?);
     cmd.arg("--version");
 
     let output = cmd.allow_failure().run_capture(build);
@@ -122,6 +122,12 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
 }
 
 pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
+    if build.kind == Kind::Format && build.top_stage != 0 {
+        eprintln!("ERROR: `x fmt` only supports stage 0.");
+        eprintln!("HELP: Use `x run rustfmt` to run in-tree rustfmt.");
+        crate::exit!(1);
+    }
+
     if !paths.is_empty() {
         eprintln!(
             "fmt error: path arguments are no longer accepted; use `--all` to format everything"
@@ -237,7 +243,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
 
     let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword
 
-    let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
+    let rustfmt_path = build.config.initial_rustfmt.clone().unwrap_or_else(|| {
         eprintln!("fmt error: `x fmt` is not supported on this channel");
         crate::exit!(1);
     });
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 3e5069225d2..c31c40e846b 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -53,7 +53,7 @@ fn is_dir_writable_for_user(dir: &Path) -> bool {
             if e.kind() == std::io::ErrorKind::PermissionDenied {
                 false
             } else {
-                panic!("Failed the write access check for the current user. {}", e);
+                panic!("Failed the write access check for the current user. {e}");
             }
         }
     }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 86af956535e..a3788197471 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -870,8 +870,8 @@ fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
     let kind = if host == target { "HOST" } else { "TARGET" };
     let target_u = target.replace('-', "_");
     env::var_os(format!("{var_base}_{target}"))
-        .or_else(|| env::var_os(format!("{}_{}", var_base, target_u)))
-        .or_else(|| env::var_os(format!("{}_{}", kind, var_base)))
+        .or_else(|| env::var_os(format!("{var_base}_{target_u}")))
+        .or_else(|| env::var_os(format!("{kind}_{var_base}")))
         .or_else(|| env::var_os(var_base))
 }
 
@@ -944,7 +944,7 @@ impl Step for Enzyme {
         }
 
         trace!(?target, "(re)building enzyme artifacts");
-        builder.info(&format!("Building Enzyme for {}", target));
+        builder.info(&format!("Building Enzyme for {target}"));
         t!(stamp.remove());
         let _time = helpers::timeit(builder);
         t!(fs::create_dir_all(&out_dir));
@@ -1229,10 +1229,9 @@ fn supported_sanitizers(
         components
             .iter()
             .map(move |c| SanitizerRuntime {
-                cmake_target: format!("clang_rt.{}_{}_dynamic", c, os),
-                path: out_dir
-                    .join(format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)),
-                name: format!("librustc-{}_rt.{}.dylib", channel, c),
+                cmake_target: format!("clang_rt.{c}_{os}_dynamic"),
+                path: out_dir.join(format!("build/lib/darwin/libclang_rt.{c}_{os}_dynamic.dylib")),
+                name: format!("librustc-{channel}_rt.{c}.dylib"),
             })
             .collect()
     };
@@ -1241,9 +1240,9 @@ fn supported_sanitizers(
         components
             .iter()
             .map(move |c| SanitizerRuntime {
-                cmake_target: format!("clang_rt.{}-{}", c, arch),
-                path: out_dir.join(format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)),
-                name: format!("librustc-{}_rt.{}.a", channel, c),
+                cmake_target: format!("clang_rt.{c}-{arch}"),
+                path: out_dir.join(format!("build/lib/{os}/libclang_rt.{c}-{arch}.a")),
+                name: format!("librustc-{channel}_rt.{c}.a"),
             })
             .collect()
     };
@@ -1362,8 +1361,8 @@ impl Step for CrtBeginEnd {
         for obj in objs {
             let base_name = unhashed_basename(&obj);
             assert!(base_name == "crtbegin" || base_name == "crtend");
-            t!(fs::copy(&obj, out_dir.join(format!("{}S.o", base_name))));
-            t!(fs::rename(&obj, out_dir.join(format!("{}.o", base_name))));
+            t!(fs::copy(&obj, out_dir.join(format!("{base_name}S.o"))));
+            t!(fs::rename(&obj, out_dir.join(format!("{base_name}.o"))));
         }
 
         out_dir
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 5cacd5b9914..0bba441c3fa 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -392,3 +392,84 @@ impl Step for CyclicStep {
         builder.ensure(CyclicStep { n: self.n.saturating_sub(1) })
     }
 }
+
+/// Step to manually run the coverage-dump tool (`./x run coverage-dump`).
+///
+/// The coverage-dump tool is an internal detail of coverage tests, so this run
+/// step is only needed when testing coverage-dump manually.
+#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
+pub struct CoverageDump;
+
+impl Step for CoverageDump {
+    type Output = ();
+
+    const DEFAULT: bool = false;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/coverage-dump")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Self {});
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let mut cmd = builder.tool_cmd(Tool::CoverageDump);
+        cmd.args(&builder.config.free_args);
+        cmd.run(builder);
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Rustfmt;
+
+impl Step for Rustfmt {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/rustfmt")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Rustfmt);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let host = builder.build.build;
+
+        // `x run` uses stage 0 by default but rustfmt does not work well with stage 0.
+        // Change the stage to 1 if it's not set explicitly.
+        let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
+            builder.top_stage
+        } else {
+            1
+        };
+
+        if stage == 0 {
+            eprintln!("rustfmt cannot be run at stage 0");
+            eprintln!("HELP: Use `x fmt` to use stage 0 rustfmt.");
+            std::process::exit(1);
+        }
+
+        let compiler = builder.compiler(stage, host);
+        let rustfmt_build = builder.ensure(tool::Rustfmt { compiler, target: host });
+
+        let mut rustfmt = tool::prepare_tool_cargo(
+            builder,
+            rustfmt_build.build_compiler,
+            Mode::ToolRustc,
+            host,
+            Kind::Run,
+            "src/tools/rustfmt",
+            SourceType::InTree,
+            &[],
+        );
+
+        rustfmt.args(["--bin", "rustfmt", "--"]);
+        rustfmt.args(builder.config.args());
+
+        rustfmt.into_cmd().run(builder);
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 9d07babe519..31ec462134d 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -552,7 +552,7 @@ Select which editor you would like to set up [default: None]: ";
 
         let mut input = String::new();
         loop {
-            print!("{}", prompt_str);
+            print!("{prompt_str}");
             io::stdout().flush()?;
             io::stdin().read_line(&mut input)?;
 
@@ -764,7 +764,7 @@ fn create_editor_settings_maybe(config: &Config, editor: &EditorKind) -> io::Res
             _ => "Created",
         };
         fs::write(&settings_path, editor.settings_template())?;
-        println!("{verb} `{}`", settings_filename);
+        println!("{verb} `{settings_filename}`");
     } else {
         println!("\n{}", editor.settings_template());
     }
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index d4fccc535a6..27791825aa0 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -54,6 +54,7 @@ impl Step for CrateBootstrap {
         run.path("src/tools/jsondoclint")
             .path("src/tools/suggest-tests")
             .path("src/tools/replace-version-placeholder")
+            .path("src/tools/coverage-dump")
             // We want `./x test tidy` to _run_ the tidy tool, not its tests.
             // So we need a separate alias to test the tidy tool itself.
             .alias("tidyselftest")
@@ -1101,7 +1102,7 @@ impl Step for Tidy {
         if builder.config.channel == "dev" || builder.config.channel == "nightly" {
             if !builder.config.json_output {
                 builder.info("fmt check");
-                if builder.initial_rustfmt().is_none() {
+                if builder.config.initial_rustfmt.is_none() {
                     let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");
                     eprintln!(
                         "\
@@ -1592,10 +1593,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             let build = builder.build.build;
             compiler = builder.compiler(compiler.stage - 1, build);
             let test_stage = compiler.stage + 1;
-            (test_stage, format!("stage{}-{}", test_stage, build))
+            (test_stage, format!("stage{test_stage}-{build}"))
         } else {
             let stage = compiler.stage;
-            (stage, format!("stage{}-{}", stage, target))
+            (stage, format!("stage{stage}-{target}"))
         };
 
         if suite.ends_with("fulldeps") {
@@ -2556,9 +2557,9 @@ fn prepare_cargo_test(
     // We skip everything on Miri as then this overwrites the libdir set up
     // by `Cargo::new` and that actually makes things go wrong.
     if builder.kind != Kind::Miri {
-        let mut dylib_path = dylib_path();
-        dylib_path.insert(0, PathBuf::from(&*builder.sysroot_target_libdir(compiler, target)));
-        cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
+        let mut dylib_paths = builder.rustc_lib_paths(compiler);
+        dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, target)));
+        helpers::add_dylib_path(dylib_paths, &mut cargo);
     }
 
     if builder.remote_tested(target) {
@@ -3553,7 +3554,7 @@ impl Step for TestFloatParse {
         builder.ensure(tool::TestFloatParse { host: self.host });
 
         // Run any unit tests in the crate
-        let cargo_test = tool::prepare_tool_cargo(
+        let mut cargo_test = tool::prepare_tool_cargo(
             builder,
             compiler,
             Mode::ToolStd,
@@ -3563,6 +3564,7 @@ impl Step for TestFloatParse {
             SourceType::InTree,
             &[],
         );
+        cargo_test.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
 
         run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder);
 
@@ -3577,6 +3579,7 @@ impl Step for TestFloatParse {
             SourceType::InTree,
             &[],
         );
+        cargo_run.allow_features(tool::TestFloatParse::ALLOW_FEATURES);
 
         if !matches!(env::var("FLOAT_PARSE_TESTS_NO_SKIP_HUGE").as_deref(), Ok("1") | Ok("true")) {
             cargo_run.args(["--", "--skip-huge"]);
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index ac568eab2e8..678aa9b01e4 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1259,6 +1259,10 @@ pub struct TestFloatParse {
     pub host: TargetSelection,
 }
 
+impl TestFloatParse {
+    pub const ALLOW_FEATURES: &'static str = "f16,cfg_target_has_reliable_f16_f128";
+}
+
 impl Step for TestFloatParse {
     type Output = ToolBuildResult;
     const ONLY_HOSTS: bool = true;
@@ -1280,7 +1284,7 @@ impl Step for TestFloatParse {
             path: "src/etc/test-float-parse",
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
-            allow_features: "",
+            allow_features: Self::ALLOW_FEATURES,
             cargo_args: Vec::new(),
             artifact_kind: ToolArtifactKind::Binary,
         })
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 36b3c95d638..e41f6f16b02 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -112,9 +112,8 @@ impl Cargo {
         let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind);
 
         match cmd_kind {
-            // No need to configure the target linker for these command types,
-            // as they don't invoke rustc at all.
-            Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {}
+            // No need to configure the target linker for these command types.
+            Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {}
             _ => {
                 cargo.configure_linker(builder);
             }
@@ -205,6 +204,8 @@ impl Cargo {
         self
     }
 
+    // FIXME(onur-ozkan): Add coverage to make sure modifications to this function
+    // doesn't cause cache invalidations (e.g., #130108).
     fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
         let target = self.target;
         let compiler = self.compiler;
@@ -1277,5 +1278,5 @@ impl Builder<'_> {
 
 pub fn cargo_profile_var(name: &str, config: &Config) -> String {
     let profile = if config.rust_optimize.is_release() { "RELEASE" } else { "DEV" };
-    format!("CARGO_PROFILE_{}_{}", profile, name)
+    format!("CARGO_PROFILE_{profile}_{name}")
 }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index c32d9c2870c..af3e3cc37b9 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -504,8 +504,8 @@ impl StepDescription {
                 match std::path::absolute(p) {
                     Ok(p) => p.strip_prefix(&builder.src).unwrap_or(&p).to_path_buf(),
                     Err(e) => {
-                        eprintln!("ERROR: {:?}", e);
-                        panic!("Due to the above error, failed to resolve path: {:?}", p);
+                        eprintln!("ERROR: {e:?}");
+                        panic!("Due to the above error, failed to resolve path: {p:?}");
                     }
                 }
             })
@@ -694,8 +694,7 @@ impl<'a> ShouldRun<'a> {
                     if !submodules_paths.iter().any(|sm_p| p.contains(sm_p)) {
                         assert!(
                             self.builder.src.join(p).exists(),
-                            "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
-                            p
+                            "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {p}"
                         );
                     }
 
@@ -961,6 +960,7 @@ impl<'a> Builder<'a> {
                 check::RunMakeSupport,
                 check::Compiletest,
                 check::FeaturesStatusDump,
+                check::CoverageDump,
             ),
             Kind::Test => describe!(
                 crate::core::build_steps::toolstate::ToolStateCheck,
@@ -1114,6 +1114,8 @@ impl<'a> Builder<'a> {
                 run::UnicodeTableGenerator,
                 run::FeaturesStatusDump,
                 run::CyclicStep,
+                run::CoverageDump,
+                run::Rustfmt,
             ),
             Kind::Setup => {
                 describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor)
@@ -1386,7 +1388,7 @@ impl<'a> Builder<'a> {
         // Windows doesn't need dylib path munging because the dlls for the
         // compiler live next to the compiler and the system will find them
         // automatically.
-        if cfg!(windows) {
+        if cfg!(any(windows, target_os = "cygwin")) {
             return;
         }
 
@@ -1534,7 +1536,7 @@ impl<'a> Builder<'a> {
             let out = step.clone().run(self);
             let dur = start.elapsed();
             let deps = self.time_spent_on_dependencies.replace(parent + dur);
-            (out, dur - deps)
+            (out, dur.saturating_sub(deps))
         };
 
         if self.config.print_step_timings && !self.config.dry_run() {
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 65a3e7667e7..3b8c3655b8d 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -3,7 +3,7 @@
 //! This module implements parsing `bootstrap.toml` configuration files to tweak
 //! how the build runs.
 
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
 use std::collections::{BTreeSet, HashMap, HashSet};
 use std::fmt::{self, Display};
 use std::hash::Hash;
@@ -406,11 +406,7 @@ pub struct Config {
     pub initial_rustc: PathBuf,
     pub initial_cargo_clippy: Option<PathBuf>,
     pub initial_sysroot: PathBuf,
-
-    #[cfg(not(test))]
-    initial_rustfmt: RefCell<RustfmtState>,
-    #[cfg(test)]
-    pub initial_rustfmt: RefCell<RustfmtState>,
+    pub initial_rustfmt: Option<PathBuf>,
 
     /// The paths to work with. For example: with `./x check foo bar` we get
     /// `paths=["foo", "bar"]`.
@@ -428,15 +424,6 @@ pub struct Config {
     pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>,
 }
 
-#[derive(Clone, Debug, Default)]
-pub enum RustfmtState {
-    SystemToolchain(PathBuf),
-    Downloaded(PathBuf),
-    Unavailable,
-    #[default]
-    LazyEvaluated,
-}
-
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
 pub enum LlvmLibunwind {
     #[default]
@@ -2448,13 +2435,8 @@ impl Config {
             });
         }
 
-        if let Some(r) = rustfmt {
-            *config.initial_rustfmt.borrow_mut() = if r.exists() {
-                RustfmtState::SystemToolchain(r)
-            } else {
-                RustfmtState::Unavailable
-            };
-        }
+        config.initial_rustfmt =
+            if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() };
 
         // Now that we've reached the end of our configuration, infer the
         // default values for all options that we haven't otherwise stored yet.
@@ -2851,25 +2833,6 @@ impl Config {
             .as_deref()
     }
 
-    pub(crate) fn initial_rustfmt(&self) -> Option<PathBuf> {
-        match &mut *self.initial_rustfmt.borrow_mut() {
-            RustfmtState::SystemToolchain(p) | RustfmtState::Downloaded(p) => Some(p.clone()),
-            RustfmtState::Unavailable => None,
-            r @ RustfmtState::LazyEvaluated => {
-                if self.dry_run() {
-                    return Some(PathBuf::new());
-                }
-                let path = self.maybe_download_rustfmt();
-                *r = if let Some(p) = &path {
-                    RustfmtState::Downloaded(p.clone())
-                } else {
-                    RustfmtState::Unavailable
-                };
-                path
-            }
-        }
-    }
-
     /// Runs a function if verbosity is greater than 0
     pub fn verbose(&self, f: impl Fn()) {
         if self.is_verbose() {
@@ -3042,7 +3005,7 @@ impl Config {
         let actual_hash = recorded
             .split_whitespace()
             .nth(2)
-            .unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
+            .unwrap_or_else(|| panic!("unexpected output `{recorded}`"));
 
         if actual_hash == checked_out_hash {
             // already checked out
@@ -3297,7 +3260,7 @@ impl Config {
             }
             StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(),
             StringOrBool::String(other) => {
-                panic!("unrecognized option for download-ci-llvm: {:?}", other)
+                panic!("unrecognized option for download-ci-llvm: {other:?}")
             }
         }
     }
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index b95d07356c1..e0c9877cd55 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -57,7 +57,7 @@ impl Config {
         if self.dry_run() {
             return;
         }
-        fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
+        fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {f:?}"));
     }
 
     /// Create a temporary directory in `out` and return its path.
@@ -112,7 +112,7 @@ impl Config {
             // The latter one does not exist on NixOS when using tmpfs as root.
             let is_nixos = match File::open("/etc/os-release") {
                 Err(e) if e.kind() == ErrorKind::NotFound => false,
-                Err(e) => panic!("failed to access /etc/os-release: {}", e),
+                Err(e) => panic!("failed to access /etc/os-release: {e}"),
                 Ok(os_release) => BufReader::new(os_release).lines().any(|l| {
                     let l = l.expect("reading /etc/os-release");
                     matches!(l.trim(), "ID=nixos" | "ID='nixos'" | "ID=\"nixos\"")
@@ -446,7 +446,7 @@ impl Config {
 
     #[cfg(test)]
     pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
-        None
+        Some(PathBuf::new())
     }
 
     /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't
@@ -455,6 +455,10 @@ impl Config {
     pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
         use build_helper::stage0_parser::VersionMetadata;
 
+        if self.dry_run() {
+            return Some(PathBuf::new());
+        }
+
         let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
         let channel = format!("{version}-{date}");
 
@@ -852,7 +856,8 @@ download-rustc = false
             t!(fs::create_dir_all(&gcc_cache));
         }
         let base = &self.stage0_metadata.config.artifacts_server;
-        let filename = format!("gcc-nightly-{}.tar.xz", self.build.triple);
+        let version = self.artifact_version_part(gcc_sha);
+        let filename = format!("gcc-{version}-{}.tar.xz", self.build.triple);
         let tarball = gcc_cache.join(&filename);
         if !tarball.exists() {
             let help_on_error = "ERROR: failed to download gcc from ci
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index eb0bf1d166a..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>>,
@@ -34,7 +34,6 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
-    "x86_64-lynx-lynxos178",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@@ -118,8 +117,8 @@ pub fn check(build: &mut Build) {
                     eprintln!(
                         "\nYour system's libstdc++ version is too old for the `llvm.download-ci-llvm` option."
                     );
-                    eprintln!("Current version detected: '{}'", version);
-                    eprintln!("Minimum required version: '{}'", LIBSTDCXX_MIN_VERSION_THRESHOLD);
+                    eprintln!("Current version detected: '{version}'");
+                    eprintln!("Minimum required version: '{LIBSTDCXX_MIN_VERSION_THRESHOLD}'");
                     eprintln!(
                         "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option."
                     );
@@ -206,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 {
@@ -279,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);
@@ -287,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/lib.rs b/src/bootstrap/src/lib.rs
index 88d181532a7..9492ffaed75 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -53,6 +53,7 @@ use tracing::{instrument, span};
 pub use utils::change_tracker::{
     CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes,
 };
+pub use utils::helpers::PanicTracker;
 
 use crate::core::build_steps::vendor::VENDOR_DIR;
 
@@ -324,7 +325,6 @@ forward! {
     tempdir() -> PathBuf,
     llvm_link_shared() -> bool,
     download_rustc() -> bool,
-    initial_rustfmt() -> Option<PathBuf>,
 }
 
 impl Build {
@@ -613,10 +613,6 @@ impl Build {
             crate::utils::job::setup(self);
         }
 
-        // Download rustfmt early so that it can be used in rust-analyzer configs.
-        trace!("downloading rustfmt early");
-        let _ = &builder::Builder::new(self).initial_rustfmt();
-
         // Handle hard-coded subcommands.
         {
             #[cfg(feature = "tracing")]
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 147b009d3f4..ceac24d4315 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -96,6 +96,7 @@ pub fn find(build: &Build) {
     let targets: HashSet<_> = match build.config.cmd {
         // We don't need to check cross targets for these commands.
         crate::Subcommand::Clean { .. }
+        | crate::Subcommand::Check { .. }
         | crate::Subcommand::Suggest { .. }
         | crate::Subcommand::Format { .. }
         | crate::Subcommand::Setup { .. } => {
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index b4a1b52dd23..43d61ce02c5 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -181,7 +181,7 @@ fn test_language_clang() {
 
 #[test]
 fn test_new_cc_build() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let cfg = new_cc_build(&build, target.clone());
     let compiler = cfg.get_compiler();
@@ -190,7 +190,7 @@ fn test_new_cc_build() {
 
 #[test]
 fn test_default_compiler_wasi() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("wasm32-wasi");
     let wasi_sdk = PathBuf::from("/wasi-sdk");
     // SAFETY: bootstrap tests run on a single thread
@@ -215,7 +215,7 @@ fn test_default_compiler_wasi() {
 
 #[test]
 fn test_default_compiler_fallback() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let mut cfg = cc::Build::new();
     let result = default_compiler(&mut cfg, Language::C, target, &build);
@@ -224,7 +224,7 @@ fn test_default_compiler_fallback() {
 
 #[test]
 fn test_find_target_with_config() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let mut target_config = Target::default();
     target_config.cc = Some(PathBuf::from("dummy-cc"));
@@ -249,7 +249,7 @@ fn test_find_target_with_config() {
 
 #[test]
 fn test_find_target_without_config() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     build.config.target_config.clear();
     find_target(&build, target.clone());
@@ -262,7 +262,7 @@ fn test_find_target_without_config() {
 
 #[test]
 fn test_find() {
-    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) });
+    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     let target2 = TargetSelection::from_user("x86_64-unknown-openbsd");
     build.targets.push(target1.clone());
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index d926185ffaf..1d0ea3ebf61 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -406,4 +406,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.",
     },
+    ChangeInfo {
+        change_id: 140732,
+        severity: ChangeSeverity::Info,
+        summary: "`./x run` now supports running in-tree `rustfmt`, e.g., `./x run rustfmt -- --check /path/to/file.rs`.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 1299fbb7d62..f2c3e8c0df4 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -7,8 +7,9 @@ use std::ffi::OsStr;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::sync::OnceLock;
+use std::thread::panicking;
 use std::time::{Instant, SystemTime, UNIX_EPOCH};
-use std::{env, fs, io, str};
+use std::{env, fs, io, panic, str};
 
 use build_helper::util::fail;
 use object::read::archive::ArchiveFile;
@@ -22,6 +23,23 @@ pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var};
 #[cfg(test)]
 mod tests;
 
+/// A wrapper around `std::panic::Location` used to track the location of panics
+/// triggered by `t` macro usage.
+pub struct PanicTracker<'a>(pub &'a panic::Location<'a>);
+
+impl Drop for PanicTracker<'_> {
+    fn drop(&mut self) {
+        if panicking() {
+            eprintln!(
+                "Panic was initiated from {}:{}:{}",
+                self.0.file(),
+                self.0.line(),
+                self.0.column()
+            );
+        }
+    }
+}
+
 /// A helper macro to `unwrap` a result except also print out details like:
 ///
 /// * The file/line of the panic
@@ -32,19 +50,21 @@ mod tests;
 /// using a `Result` with `try!`, but this may change one day...
 #[macro_export]
 macro_rules! t {
-    ($e:expr) => {
+    ($e:expr) => {{
+        let _panic_guard = $crate::PanicTracker(std::panic::Location::caller());
         match $e {
             Ok(e) => e,
             Err(e) => panic!("{} failed with {}", stringify!($e), e),
         }
-    };
+    }};
     // it can show extra info in the second parameter
-    ($e:expr, $extra:expr) => {
+    ($e:expr, $extra:expr) => {{
+        let _panic_guard = $crate::PanicTracker(std::panic::Location::caller());
         match $e {
             Ok(e) => e,
             Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra),
         }
-    };
+    }};
 }
 
 pub use t;
@@ -110,7 +130,7 @@ pub fn is_debug_info(name: &str) -> bool {
 /// Returns the corresponding relative library directory that the compiler's
 /// dylibs will be found in.
 pub fn libdir(target: TargetSelection) -> &'static str {
-    if target.is_windows() { "bin" } else { "lib" }
+    if target.is_windows() || target.contains("cygwin") { "bin" } else { "lib" }
 }
 
 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
@@ -309,7 +329,7 @@ pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> {
         Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")),
     };
 
-    let command = format!("{:?}", cmd);
+    let command = format!("{cmd:?}");
 
     move || {
         let output = child.wait_with_output().unwrap();
@@ -520,7 +540,7 @@ where
     use std::fmt::Write;
 
     input.as_ref().iter().fold(String::with_capacity(input.as_ref().len() * 2), |mut acc, &byte| {
-        write!(&mut acc, "{:02x}", byte).expect("Failed to write byte to the hex String.");
+        write!(&mut acc, "{byte:02x}").expect("Failed to write byte to the hex String.");
         acc
     })
 }
diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs
index 4949518de79..887deb41ca8 100644
--- a/src/bootstrap/src/utils/job.rs
+++ b/src/bootstrap/src/utils/job.rs
@@ -66,7 +66,6 @@ mod for_windows {
             // Enable the Windows Error Reporting dialog which msys disables,
             // so we can JIT debug rustc
             let mode = SetErrorMode(THREAD_ERROR_MODE::default());
-            let mode = THREAD_ERROR_MODE(mode);
             SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
 
             // Create a new job object for us to use
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 7b206c3ffe8..08e1c21e58e 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -20,7 +20,7 @@ use std::str::FromStr;
 /// Returns the environment variable which the dynamic library lookup path
 /// resides in for this platform.
 pub fn dylib_path_var() -> &'static str {
-    if cfg!(target_os = "windows") {
+    if cfg!(any(target_os = "windows", target_os = "cygwin")) {
         "PATH"
     } else if cfg!(target_vendor = "apple") {
         "DYLD_LIBRARY_PATH"
@@ -90,7 +90,7 @@ pub fn maybe_dump(dump_name: String, cmd: &Command) {
 
         let mut file = OpenOptions::new().create(true).append(true).open(dump_file).unwrap();
 
-        let cmd_dump = format!("{:?}\n", cmd);
+        let cmd_dump = format!("{cmd:?}\n");
         let cmd_dump = cmd_dump.replace(&env::var("BUILD_OUT").unwrap(), "${BUILD_OUT}");
         let cmd_dump = cmd_dump.replace(&env::var("CARGO_HOME").unwrap(), "${CARGO_HOME}");
 
diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py
index 3d9dc86734f..19a39f34953 100755
--- a/src/ci/cpu-usage-over-time.py
+++ b/src/ci/cpu-usage-over-time.py
@@ -170,7 +170,7 @@ print("Time,Idle")
 while True:
     time.sleep(1)
     next_state = State()
-    now = datetime.datetime.utcnow().isoformat()
+    now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None).isoformat()
     idle = next_state.idle_since(cur_state)
     print("%s,%s" % (now, idle))
     sys.stdout.flush()
diff --git a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile
index 2c514fa0d4d..adeaf809f42 100644
--- a/src/ci/docker/host-x86_64/dist-ohos/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-ohos-aarch64/Dockerfile
@@ -27,36 +27,18 @@ RUN sh /scripts/ohos-openssl.sh
 
 COPY scripts/ohos/aarch64-unknown-linux-ohos-clang.sh /usr/local/bin/
 COPY scripts/ohos/aarch64-unknown-linux-ohos-clang++.sh /usr/local/bin/
-COPY scripts/ohos/armv7-unknown-linux-ohos-clang.sh /usr/local/bin/
-COPY scripts/ohos/armv7-unknown-linux-ohos-clang++.sh /usr/local/bin/
-COPY scripts/ohos/x86_64-unknown-linux-ohos-clang.sh /usr/local/bin/
-COPY scripts/ohos/x86_64-unknown-linux-ohos-clang++.sh /usr/local/bin/
 
 # env
 ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/arm64-v8a
-ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/armeabi-v7a
-ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/x86_64
 
 ENV AARCH64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1
-ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1
-ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1
 
 ENV TARGETS=aarch64-unknown-linux-ohos
-ENV TARGETS=$TARGETS,armv7-unknown-linux-ohos
-ENV TARGETS=$TARGETS,x86_64-unknown-linux-ohos
 
 ENV \
     CC_aarch64_unknown_linux_ohos=/usr/local/bin/aarch64-unknown-linux-ohos-clang.sh \
     AR_aarch64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \
     CXX_aarch64_unknown_linux_ohos=/usr/local/bin/aarch64-unknown-linux-ohos-clang++.sh
-ENV \
-    CC_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang.sh \
-    AR_armv7_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \
-    CXX_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang++.sh
-ENV \
-    CC_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang.sh \
-    AR_x86_64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \
-    CXX_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang++.sh
 
 ENV RUST_CONFIGURE_ARGS \
     --enable-profiler \
diff --git a/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile
new file mode 100644
index 00000000000..2a23d8aec23
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-ohos-armv7/Dockerfile
@@ -0,0 +1,53 @@
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    g++ \
+    make \
+    ninja-build \
+    file \
+    curl \
+    ca-certificates \
+    python3 \
+    git \
+    cmake \
+    sudo \
+    gdb \
+    libssl-dev \
+    pkg-config \
+    xz-utils \
+    unzip \
+    && rm -rf /var/lib/apt/lists/*
+
+COPY scripts/ohos-sdk.sh /scripts/
+RUN sh /scripts/ohos-sdk.sh
+
+COPY scripts/ohos-openssl.sh /scripts/
+RUN sh /scripts/ohos-openssl.sh
+
+COPY scripts/ohos/armv7-unknown-linux-ohos-clang.sh /usr/local/bin/
+COPY scripts/ohos/armv7-unknown-linux-ohos-clang++.sh /usr/local/bin/
+
+# env
+ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/armeabi-v7a
+
+ENV ARMV7_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1
+
+ENV TARGETS=armv7-unknown-linux-ohos
+
+ENV \
+    CC_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang.sh \
+    AR_armv7_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \
+    CXX_armv7_unknown_linux_ohos=/usr/local/bin/armv7-unknown-linux-ohos-clang++.sh
+
+ENV RUST_CONFIGURE_ARGS \
+    --enable-profiler \
+    --disable-docs \
+    --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \
+    --enable-extended \
+    --enable-sanitizers
+
+ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile
new file mode 100644
index 00000000000..98e402adf2a
--- /dev/null
+++ b/src/ci/docker/host-x86_64/dist-ohos-x86_64/Dockerfile
@@ -0,0 +1,53 @@
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    g++ \
+    make \
+    ninja-build \
+    file \
+    curl \
+    ca-certificates \
+    python3 \
+    git \
+    cmake \
+    sudo \
+    gdb \
+    libssl-dev \
+    pkg-config \
+    xz-utils \
+    unzip \
+    && rm -rf /var/lib/apt/lists/*
+
+COPY scripts/ohos-sdk.sh /scripts/
+RUN sh /scripts/ohos-sdk.sh
+
+COPY scripts/ohos-openssl.sh /scripts/
+RUN sh /scripts/ohos-openssl.sh
+
+COPY scripts/ohos/x86_64-unknown-linux-ohos-clang.sh /usr/local/bin/
+COPY scripts/ohos/x86_64-unknown-linux-ohos-clang++.sh /usr/local/bin/
+
+# env
+ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_DIR=/opt/ohos-openssl/prelude/x86_64
+
+ENV X86_64_UNKNOWN_LINUX_OHOS_OPENSSL_NO_VENDOR=1
+
+ENV TARGETS=x86_64-unknown-linux-ohos
+
+ENV \
+    CC_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang.sh \
+    AR_x86_64_unknown_linux_ohos=/opt/ohos-sdk/native/llvm/bin/llvm-ar \
+    CXX_x86_64_unknown_linux_ohos=/usr/local/bin/x86_64-unknown-linux-ohos-clang++.sh
+
+ENV RUST_CONFIGURE_ARGS \
+    --enable-profiler \
+    --disable-docs \
+    --tools=cargo,clippy,rustdocs,rustfmt,rust-analyzer,rust-analyzer-proc-macro-srv,analysis,src,wasm-component-ld \
+    --enable-extended \
+    --enable-sanitizers
+
+ENV SCRIPT python3 ../x.py dist --host=$TARGETS --target $TARGETS
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 3428dd4826a..e15121e0f31 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.20.3
\ No newline at end of file
+0.20.6
\ No newline at end of file
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index 28c035daa5d..9222710b843 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -40,6 +40,14 @@ if [ -z "${PR_CI_JOB:-}" ]; then
 else
     python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri
 fi
+# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR
+# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug
+# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can
+# adjust their expectations if needed. This can change the output of the tests so we ignore that,
+# we only ensure that all assertions still pass.
+MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \
+  MIRI_SKIP_UI_CHECKS=1 \
+  python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic
 # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc.
 # Also cover some other targets via cross-testing, in particular all tier 1 targets.
 case $HOST_TARGET in
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index afcc092e78e..42ad5acbdac 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -35,6 +35,8 @@ runners:
     os: windows-2022
     <<: *base-job
 
+  # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
+  # insufficient disk space.
   - &job-windows-25
     os: windows-2025
     <<: *base-job
@@ -186,8 +188,14 @@ auto:
   - name: dist-loongarch64-musl
     <<: *job-linux-4c
 
-  - name: dist-ohos
-    <<: *job-linux-4c-largedisk
+  - name: dist-ohos-aarch64
+    <<: *job-linux-4c
+
+  - name: dist-ohos-armv7
+    <<: *job-linux-4c
+
+  - name: dist-ohos-x86_64
+    <<: *job-linux-4c
 
   - name: dist-powerpc-linux
     <<: *job-linux-4c
@@ -476,13 +484,17 @@ auto:
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
       SCRIPT: make ci-msvc-py
-    <<: *job-windows-25
+    # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
+    # insufficient disk space.
+    <<: *job-windows
 
   - name: x86_64-msvc-2
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-sanitizers --enable-profiler
       SCRIPT: make ci-msvc-ps1
-    <<: *job-windows-25
+    # FIXME(#141022): Windows Server 2025 20250504.1.0 currently experiences
+    # insufficient disk space.
+    <<: *job-windows
 
   # i686-msvc is split into two jobs to run tests in parallel.
   - name: i686-msvc-1
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 467f45637b73ec6aa70fb36bc3054bb50b8967e
+Subproject 1b1bb49babd65c732468cfa515b0c009bd1d26b
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 3bf3402aea982b876eb56c87da17b0685c6461d
+Subproject acd0231ebc74849f6a8907b5e646ce86721aad7
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 0d7964d5b22cf920237ef1282d869564b4883b8
+Subproject c9d151f9147c4808c77f0375ba3fa5d54443cb9
diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
index 415d0dc397d..daf5223cbd4 100644
--- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml
+++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml
@@ -14,7 +14,7 @@ jobs:
     if: github.repository == 'rust-lang/rustc-dev-guide'
     runs-on: ubuntu-latest
     env:
-      MDBOOK_VERSION: 0.4.21
+      MDBOOK_VERSION: 0.4.48
       MDBOOK_LINKCHECK2_VERSION: 0.9.1
       MDBOOK_MERMAID_VERSION: 0.12.6
       MDBOOK_TOC_VERSION: 0.11.2
diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md
index 08158801788..0425c15f83c 100644
--- a/src/doc/rustc-dev-guide/README.md
+++ b/src/doc/rustc-dev-guide/README.md
@@ -91,6 +91,16 @@ Older versions of `josh-proxy` may not round trip commits losslessly so it is im
 3) Push the branch to your fork and create a PR into `rustc-dev-guide`
 
 ### Push changes from this repository into `rust-lang/rust`
+
+NOTE: If you use Git protocol to push to your fork of `rust-lang/rust`,
+ensure that you have this entry in your Git config,
+else the 2 steps that follow would prompt for a username and password:
+
+```
+[url "git@github.com:"]
+insteadOf = "https://github.com/"
+```
+
 1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
     ```
     cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock
index 6326b2daf12..7107547332f 100644
--- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock
+++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "aho-corasick"
@@ -28,21 +28,24 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "bumpalo"
-version = "3.16.0"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "cc"
-version = "1.0.106"
+version = "1.2.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2"
+checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -52,27 +55,27 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.38"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
  "wasm-bindgen",
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "date-check"
-version = "0.1.0"
+version = "0.0.0"
 dependencies = [
  "chrono",
  "glob",
@@ -81,20 +84,21 @@ dependencies = [
 
 [[package]]
 name = "glob"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.60"
+version = "0.1.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
+ "log",
  "wasm-bindgen",
  "windows-core",
 ]
@@ -110,24 +114,25 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.69"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
+ "once_cell",
  "wasm-bindgen",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.172"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "memchr"
@@ -146,33 +151,33 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.36"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "regex"
-version = "1.10.5"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -182,9 +187,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -193,15 +198,27 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "syn"
-version = "2.0.70"
+version = "2.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -210,29 +227,30 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
+ "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn",
@@ -241,9 +259,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -251,9 +269,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -264,79 +282,68 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.92"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "windows-core"
-version = "0.52.0"
+version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-targets",
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
+name = "windows-implement"
+version = "0.60.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
+name = "windows-interface"
+version = "0.59.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
+name = "windows-link"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
+name = "windows-result"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+dependencies = [
+ "windows-link",
+]
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
+name = "windows-strings"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+dependencies = [
+ "windows-link",
+]
diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml
index 472529511d0..f49e6d0db94 100644
--- a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml
+++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml
@@ -1,10 +1,6 @@
 [package]
 name = "date-check"
-version = "0.1.0"
-authors = ["Noah Lev <camelidcamel@gmail.com>"]
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+edition = "2024"
 
 [dependencies]
 glob = "0.3"
diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
index 9af69dbbf3f..0a32f4e9b7b 100644
--- a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
+++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs
@@ -114,7 +114,7 @@ fn filter_dates(
 fn main() {
     let mut args = env::args();
     if args.len() == 1 {
-        eprintln!("error: expected root Markdown directory as CLI argument");
+        eprintln!("error: expected root of Markdown directory as CLI argument");
         process::exit(1);
     }
     let root_dir = args.nth(1).unwrap();
diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock
index 844518628c4..a8183a740db 100644
--- a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock
+++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock
@@ -161,7 +161,7 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
 
 [[package]]
 name = "josh-sync"
-version = "0.1.0"
+version = "0.0.0"
 dependencies = [
  "anyhow",
  "clap",
diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml
index 81d0d1ebd22..1f8bf2a0093 100644
--- a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml
+++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "josh-sync"
-version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 anyhow = "1.0.95"
diff --git a/src/doc/rustc-dev-guide/josh-sync/src/main.rs b/src/doc/rustc-dev-guide/josh-sync/src/main.rs
index 175f016f739..aeedee5be22 100644
--- a/src/doc/rustc-dev-guide/josh-sync/src/main.rs
+++ b/src/doc/rustc-dev-guide/josh-sync/src/main.rs
@@ -1,4 +1,5 @@
 use clap::Parser;
+
 use crate::sync::{GitSync, RustcPullError};
 
 mod sync;
@@ -11,10 +12,7 @@ enum Args {
     /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given
     /// GitHub `username`.
     /// The pushed branch should then be merged into the `rustc` repository.
-    RustcPush {
-        branch: String,
-        github_username: String
-    }
+    RustcPush { branch: String, github_username: String },
 }
 
 fn main() -> anyhow::Result<()> {
diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
index cd64be63670..ed38d1403a0 100644
--- a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
+++ b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
@@ -1,10 +1,11 @@
+use std::io::Write;
 use std::ops::Not;
 use std::path::PathBuf;
-use std::{env, net, process};
-use std::io::Write;
 use std::time::Duration;
-use anyhow::{anyhow, bail, Context};
-use xshell::{cmd, Shell};
+use std::{env, net, process};
+
+use anyhow::{Context, anyhow, bail};
+use xshell::{Shell, cmd};
 
 /// Used for rustc syncs.
 const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide";
@@ -15,10 +16,13 @@ pub enum RustcPullError {
     /// No changes are available to be pulled.
     NothingToPull,
     /// A rustc-pull has failed, probably a git operation error has occurred.
-    PullFailed(anyhow::Error)
+    PullFailed(anyhow::Error),
 }
 
-impl<E> From<E> for RustcPullError where E: Into<anyhow::Error> {
+impl<E> From<E> for RustcPullError
+where
+    E: Into<anyhow::Error>,
+{
     fn from(error: E) -> Self {
         Self::PullFailed(error.into())
     }
@@ -32,9 +36,7 @@ pub struct GitSync {
 /// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236).
 impl GitSync {
     pub fn from_current_dir() -> anyhow::Result<Self> {
-        Ok(Self {
-            dir: std::env::current_dir()?
-        })
+        Ok(Self { dir: std::env::current_dir()? })
     }
 
     pub fn rustc_pull(&self, commit: Option<String>) -> Result<(), RustcPullError> {
@@ -51,7 +53,10 @@ impl GitSync {
         })?;
         // Make sure the repo is clean.
         if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
-            return Err(anyhow::anyhow!("working directory must be clean before performing rustc pull").into());
+            return Err(anyhow::anyhow!(
+                "working directory must be clean before performing rustc pull"
+            )
+            .into());
         }
         // Make sure josh is running.
         let josh = Self::start_josh()?;
@@ -94,7 +99,8 @@ impl GitSync {
         };
         let num_roots_before = num_roots()?;
 
-        let sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
+        let sha =
+            cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
 
         // Merge the fetched commit.
         const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
@@ -102,18 +108,24 @@ impl GitSync {
             .run()
             .context("FAILED to merge new commits, something went wrong")?;
 
-        let current_sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
+        let current_sha =
+            cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
         if current_sha == sha {
             cmd!(sh, "git reset --hard HEAD^")
                 .run()
                 .expect("FAILED to clean up after creating the preparation commit");
-            eprintln!("No merge was performed, no changes to pull were found. Rolled back the preparation commit.");
+            eprintln!(
+                "No merge was performed, no changes to pull were found. Rolled back the preparation commit."
+            );
             return Err(RustcPullError::NothingToPull);
         }
 
         // Check that the number of roots did not increase.
         if num_roots()? != num_roots_before {
-            return Err(anyhow::anyhow!("Josh created a new root commit. This is probably not the history you want.").into());
+            return Err(anyhow::anyhow!(
+                "Josh created a new root commit. This is probably not the history you want."
+            )
+            .into());
         }
 
         drop(josh);
@@ -194,7 +206,7 @@ impl GitSync {
         );
         println!(
             // Open PR with `subtree update` title to silence the `no-merges` triagebot check
-            "    https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=Rustc+dev+guide+subtree+update&body=r?+@ghost"
+            "    https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
         );
 
         drop(josh);
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 67fa25f2228..5e4266f61da 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-deb947971c8748f5c6203548ce4af9022f21eaf0
+414482f6a0d4e7290f614300581a0b55442552a3
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index d6ec803a60a..31119496e75 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -157,6 +157,7 @@
     - [ADTs and Generic Arguments](./ty_module/generic_arguments.md)
     - [Parameter types/consts/regions](./ty_module/param_ty_const_regions.md)
 - [`TypeFolder` and `TypeFoldable`](./ty-fold.md)
+- [Aliases and Normalization](./normalization.md)
 - [Typing/Param Envs](./typing_parameter_envs.md)
 - [Type inference](./type-inference.md)
 - [Trait solving](./traits/resolution.md)
@@ -176,7 +177,6 @@
         - [Coinduction](./solve/coinduction.md)
         - [Caching](./solve/caching.md)
         - [Proof trees](./solve/proof-trees.md)
-        - [Normalization](./solve/normalization.md)
         - [Opaque types](./solve/opaque-types.md)
         - [Significant changes and quirks](./solve/significant-changes.md)
     - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)
diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md
index f3c11395523..c9b28dc43a6 100644
--- a/src/doc/rustc-dev-guide/src/autodiff/installation.md
+++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md
@@ -1,6 +1,6 @@
 # Installation
 
-In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target.
+In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target.
 
 ## Build instructions
 
diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
index 8e6725c54ef..55436261fde 100644
--- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
+++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
@@ -80,41 +80,11 @@ approachable and practical; it may make sense to direct users to an RFC or some
 other issue for the full details. The issue also serves as a place where users
 can comment with questions or other concerns.
 
-A template for these breaking-change tracking issues can be found below. An
-example of how such an issue should look can be [found
+A template for these breaking-change tracking issues can be found
+[here][template]. An example of how such an issue should look can be [found
 here][breaking-change-issue].
 
-The issue should be tagged with (at least) `B-unstable` and `T-compiler`.
-
-### Tracking issue template
-
-This is a template to use for tracking issues:
-
-```
-This is the **summary issue** for the `YOUR_LINT_NAME_HERE`
-future-compatibility warning and other related errors. The goal of
-this page is describe why this change was made and how you can fix
-code that is affected by it. It also provides a place to ask questions
-or register a complaint if you feel the change should not be made. For
-more information on the policy around future-compatibility warnings,
-see our [breaking change policy guidelines][guidelines].
-
-[guidelines]: LINK_TO_THIS_RFC
-
-#### What is the warning for?
-
-*Describe the conditions that trigger the warning and how they can be
-fixed. Also explain why the change was made.**
-
-#### When will this warning become a hard error?
-
-At the beginning of each 6-week release cycle, the Rust compiler team
-will review the set of outstanding future compatibility warnings and
-nominate some of them for **Final Comment Period**. Toward the end of
-the cycle, we will review any comments and make a final determination
-whether to convert the warning into a hard error or remove it
-entirely.
-```
+[template]: https://github.com/rust-lang/rust/issues/new?template=tracking_issue_future.md
 
 ### Issuing future compatibility warnings
 
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md
index f72918c8377..7f53097824c 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md
@@ -6,8 +6,8 @@ of the same compiler.
 
 This raises a chicken-and-egg paradox: where did the first compiler come from?
 It must have been written in a different language. In Rust's case it was
-[written in OCaml][ocaml-compiler]. However it was abandoned long ago and the
-only way to build a modern version of rustc is a slightly less modern
+[written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the
+only way to build a modern version of rustc is with a slightly less modern
 version.
 
 This is exactly how `x.py` works: it downloads the current beta release of
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md
index ffcfe259625..a2930b3e427 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md
@@ -8,8 +8,8 @@ the same compiler.
 
 This raises a chicken-and-egg paradox: where did the first compiler come from?
 It must have been written in a different language. In Rust's case it was
-[written in OCaml][ocaml-compiler]. However it was abandoned long ago and the
-only way to build a modern version of `rustc` is a slightly less modern version.
+[written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the
+only way to build a modern version of `rustc` is with a slightly less modern version.
 
 This is exactly how [`./x.py`] works: it downloads the current beta release of
 `rustc`, then uses it to compile the new compiler.
diff --git a/src/doc/rustc-dev-guide/src/compiler-src.md b/src/doc/rustc-dev-guide/src/compiler-src.md
index c538fc8b788..00aa9622684 100644
--- a/src/doc/rustc-dev-guide/src/compiler-src.md
+++ b/src/doc/rustc-dev-guide/src/compiler-src.md
@@ -62,21 +62,20 @@ huge. There is also the `rustc` crate which is the actual binary (i.e. the
 [`rustc_driver`] crate, which drives the various parts of compilation in other
 crates.
 
-The dependency structure of these crates is complex, but roughly it is
+The dependency order of these crates is complex, but roughly it is
 something like this:
 
-- `rustc` (the binary) calls [`rustc_driver::main`][main].
-    - [`rustc_driver`] depends on a lot of other crates, but the main one is
-      [`rustc_interface`].
-        - [`rustc_interface`] depends on most of the other compiler crates. It
-          is a fairly generic interface for driving the whole compilation.
-            - Most of the other `rustc_*` crates depend on [`rustc_middle`],
-              which defines a lot of central data structures in the compiler.
-                - [`rustc_middle`] and most of the other crates depend on a
-                  handful of crates representing the early parts of the
-                  compiler (e.g. the parser), fundamental data structures (e.g.
-                  [`Span`]), or error reporting: [`rustc_data_structures`],
-                  [`rustc_span`], [`rustc_errors`], etc.
+1. `rustc` (the binary) calls [`rustc_driver::main`][main].
+1. [`rustc_driver`] depends on a lot of other crates, but the main one is
+   [`rustc_interface`].
+1. [`rustc_interface`] depends on most of the other compiler crates. It is a
+   fairly generic interface for driving the whole compilation.
+1. Most of the other `rustc_*` crates depend on [`rustc_middle`], which defines
+   a lot of central data structures in the compiler.
+1. [`rustc_middle`] and most of the other crates depend on a handful of crates
+   representing the early parts of the compiler (e.g. the parser), fundamental
+   data structures (e.g. [`Span`]), or error reporting:
+   [`rustc_data_structures`], [`rustc_span`], [`rustc_errors`], etc.
 
 [`rustc_data_structures`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/index.html
 [`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/index.html
@@ -87,8 +86,12 @@ something like this:
 [`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
 [main]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.main.html
 
-You can see the exact dependencies by reading the [`Cargo.toml`] for the various
-crates, just like a normal Rust crate.
+You can see the exact dependencies by running `cargo tree`,
+just like you would for any other Rust package:
+
+```console
+cargo tree --package rustc_driver
+```
 
 One final thing: [`src/llvm-project`] is a submodule for our fork of LLVM.
 During bootstrapping, LLVM is built and the [`compiler/rustc_llvm`] crate
diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md
index ea207167791..9a92d4ebcb5 100644
--- a/src/doc/rustc-dev-guide/src/guides/editions.md
+++ b/src/doc/rustc-dev-guide/src/guides/editions.md
@@ -193,6 +193,23 @@ When a user runs `cargo fix --edition`, cargo will pass the `--force-warn rust-2
 flag to force all of these lints to appear during the edition migration.
 Cargo also passes `--cap-lints=allow` so that no other lints interfere with the edition migration.
 
+Make sure that the example code sets the correct edition. The example should illustrate the previous edition, and show what the migration warning would look like. For example, this lint for a 2024 migration shows an example in 2021:
+
+```rust,ignore
+declare_lint! {
+    /// The `keyword_idents_2024` lint detects ...
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021
+    /// #![warn(keyword_idents_2024)]
+    /// fn gen() {}
+    /// ```
+    ///
+    /// {{produces}}
+}
+```
+
 Migration lints can be either `Allow` or `Warn` by default.
 If it is `Allow`, users usually won't see this warning unless they are doing an edition migration
 manually or there is a problem during the migration.
@@ -334,3 +351,40 @@ In general it is recommended to avoid these special cases except for very high v
 [into-iter]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html
 [panic-macro]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html
 [`non_fmt_panics`]: https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#non-fmt-panics
+
+### Migrating the standard library edition
+
+Updating the edition of the standard library itself roughly involves the following process:
+
+- Wait until the newly stabilized edition has reached beta and the bootstrap compiler has been updated.
+- Apply migration lints. This can be an involved process since some code is in external submodules[^std-submodules], and the standard library makes heavy use of conditional compilation. Also, running `cargo fix --edition` can be impractical on the standard library itself. One approach is to individually add `#![warn(...)]` at the top of each crate for each lint, run `./x check library`, apply the migrations, remove the `#![warn(...)]` and commit each migration separately. You'll likely need to run `./x check` with `--target` for many different targets to get full coverage (otherwise you'll likely spend days or weeks getting CI to pass)[^ed-docker]. See also the [advanced migration guide] for more tips.
+    - Apply migrations to [`backtrace-rs`]. [Example for 2024](https://github.com/rust-lang/backtrace-rs/pull/700). Note that this doesn't update the edition of the crate itself because that is published independently on crates.io, and that would otherwise restrict the minimum Rust version. Consider adding some `#![deny()]` attributes to avoid regressions until its edition gets updated.
+    - Apply migrations to [`stdarch`], and update its edition, and formatting. [Example for 2024](https://github.com/rust-lang/stdarch/pull/1710).
+    - Post PRs to update the backtrace and stdarch submodules, and wait for those to land.
+    - Apply migration lints to the standard library crates, and update their edition. I recommend working one crate at a time starting with `core`. [Example for 2024](https://github.com/rust-lang/rust/pull/138162).
+
+[^std-submodules]: This will hopefully change in the future to pull these submodules into `rust-lang/rust`.
+[^ed-docker]: You'll also likely need to do a lot of testing for different targets, and this is where [docker testing](../tests/docker.md) comes in handy.
+
+[advanced migration guide]: https://doc.rust-lang.org/nightly/edition-guide/editions/advanced-migrations.html
+[`backtrace-rs`]: https://github.com/rust-lang/backtrace-rs/
+[`stdarch`]: https://github.com/rust-lang/stdarch/
+
+## Stabilizing an edition
+
+After the edition team has given the go-ahead, the process for stabilizing an edition is roughly:
+
+- Update [`LATEST_STABLE_EDITION`].
+- Update [`Edition::is_stable`].
+- Hunt and find any document that refers to edition by number, and update it:
+    - [`--edition` flag](https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/command-line-arguments.md#--edition-specify-the-edition-to-use)
+    - [Rustdoc attributes](https://github.com/rust-lang/rust/blob/master/src/doc/rustdoc/src/write-documentation/documentation-tests.md#attributes)
+- Clean up any tests that use the `//@ edition` header to remove the `-Zunstable-options` flag to ensure they are indeed stable. Note: Ideally this should be automated, see [#133582].
+- Bless any tests that change.
+- Update `lint-docs` to default to the new edition.
+
+See [example for 2024](https://github.com/rust-lang/rust/pull/133349).
+
+[`LATEST_STABLE_EDITION`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/edition/constant.LATEST_STABLE_EDITION.html
+[`Edition::is_stable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/edition/enum.Edition.html#method.is_stable
+[#133582]: https://github.com/rust-lang/rust/issues/133582
diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md
index ebab56ad20a..a90f717004f 100644
--- a/src/doc/rustc-dev-guide/src/macro-expansion.md
+++ b/src/doc/rustc-dev-guide/src/macro-expansion.md
@@ -2,9 +2,6 @@
 
 <!-- toc -->
 
-> N.B. [`rustc_ast`], [`rustc_expand`], and [`rustc_builtin_macros`] are all
-> undergoing refactoring, so some of the links in this chapter may be broken.
-
 Rust has a very powerful macro system. In the previous chapter, we saw how
 the parser sets aside macros to be expanded (using temporary [placeholders]).
 This chapter is about the process of expanding those macros iteratively until
@@ -12,9 +9,6 @@ we have a complete [*Abstract Syntax Tree* (AST)][ast] for our crate with no
 unexpanded macros (or a compile error).
 
 [ast]: ./ast-validation.md
-[`rustc_ast`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/index.html
-[`rustc_expand`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/index.html
-[`rustc_builtin_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_builtin_macros/index.html
 [placeholders]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/placeholders/index.html
 
 First, we discuss the algorithm that expands and integrates macro output into
diff --git a/src/doc/rustc-dev-guide/src/mir/dataflow.md b/src/doc/rustc-dev-guide/src/mir/dataflow.md
index f31da5ca22e..85e57dd839b 100644
--- a/src/doc/rustc-dev-guide/src/mir/dataflow.md
+++ b/src/doc/rustc-dev-guide/src/mir/dataflow.md
@@ -148,8 +148,7 @@ whereas this code uses [`ResultsCursor`]:
 
 ```rust,ignore
 let mut results = MyAnalysis::new()
-    .into_engine(tcx, body, def_id)
-    .iterate_to_fixpoint()
+    .iterate_to_fixpoint(tcx, body, None);
     .into_results_cursor(body);
 
 // Inspect the fixpoint state immediately before each `Drop` terminator.
diff --git a/src/doc/rustc-dev-guide/src/normalization.md b/src/doc/rustc-dev-guide/src/normalization.md
new file mode 100644
index 00000000000..ef530ccc5ed
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/normalization.md
@@ -0,0 +1,309 @@
+# Aliases and Normalization
+
+<!-- toc -->
+
+## Aliases
+
+In Rust there are a number of types that are considered equal to some "underlying" type, for example inherent associated types, trait associated types, free type aliases (`type Foo = u32`), and opaque types (`-> impl RPIT`). We consider such types to be "aliases", alias types are represented by the [`TyKind::Alias`][tykind_alias] variant, with the kind of alias tracked by the [`AliasTyKind`][aliaskind] enum.
+
+Normalization is the process of taking these alias types and replacing them with the underlying type that they are equal to. For example given some type alias `type Foo = u32`, normalizing `Foo` would give `u32`.
+
+The concept of an alias is not unique to *types* and the concept also applies to constants/const generics. However, right now in the compiler we don't really treat const aliases as a "first class concept" so this chapter mostly discusses things in the context of types (even though the concepts transfer just fine).
+
+[tykind_alias]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.TyKind.html#variant.Alias
+[aliaskind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.AliasTyKind.html
+
+### Rigid, Ambiguous and Unnormalized Aliases
+
+Aliases can either be "rigid", "ambiguous", or simply unnormalized.
+
+We consider types to be rigid if their "shape" isn't going to change, for example `Box` is rigid as no amount of normalization can turn a `Box` into a `u32`, whereas `<vec::IntoIter<u32> as Iterator>::Item` is not rigid as it can be normalized to `u32`.
+
+Aliases are rigid when we will never be able to normalize them further. A concrete example of a *rigid* alias would be `<T as Iterator>::Item` in an environment where there is no `T: Iterator<Item = ...>` bound, only a `T: Iterator` bound:
+```rust
+fn foo<T: Iterator>() {
+    // This alias is *rigid*
+    let _: <T as Iterator>::Item;
+}
+
+fn bar<T: Iterator<Item = u32>>() {
+    // This alias is *not* rigid as it can be normalized to `u32`
+    let _: <T as Iterator>::Item;
+}
+```
+
+When an alias can't yet be normalized but may wind up normalizable in the [current environment](./typing_parameter_envs.md), we consider it to be an "ambiguous" alias. This can occur when an alias contains inference variables which prevent being able to determine how the trait is implemented:
+```rust
+fn foo<T: Iterator, U: Iterator>() {
+    // This alias is considered to be "ambiguous"
+    let _: <_ as Iterator>::Item;
+}
+```
+
+The reason we call them "ambiguous" aliases is because its *ambiguous* whether this is a rigid alias or not.
+
+The source of the `_: Iterator` trait impl is *ambiguous* (i.e. unknown), it could be some `impl Iterator for u32` or it could be some `T: Iterator` trait bound, we don't know yet. Depending on why `_: Iterator` holds the alias could be an unnormalized alias or it could be a rigid alias; it's *ambiguous* what kind of alias this is.
+
+Finally, an alias can just be unnormalized, `<Vec<u32> as IntoIterator>::Iter` is an unnormalized alias as it can already be normalized to `std::vec::IntoIter<u32>`, it just hasn't been done yet.
+
+---
+
+It is worth noting that Free and Inherent aliases cannot be rigid or ambiguous as naming them also implies having resolved the definition of the alias, which specifies the underlying type of the alias.
+
+### Diverging Aliases
+
+An alias is considered to "diverge" if its definition does not specify an underlying non-alias type to normalize to. A concrete example of diverging aliases:
+```rust
+type Diverges = Diverges;
+
+trait Trait {
+    type DivergingAssoc;
+}
+impl Trait for () {
+    type DivergingAssoc = <() as Trait>::DivergingAssoc;
+}
+```
+In this example both `Diverges` and `DivergingAssoc` are "trivial" cases of diverging type aliases where they have been defined as being equal to themselves. There is no underlying type that `Diverges` can ever be normalized to.
+
+We generally try to error when diverging aliases are defined, but this is entirely a "best effort" check. In the previous example the definitions are "simple enough" to be detected and so errors are emitted. However, in more complex cases, or cases where only some instantiations of generic parameters would result in a diverging alias, we don't emit an error:
+```rust
+trait Trait {
+    type DivergingAssoc<U: Trait>;
+}
+impl<T: ?Sized> Trait for T {
+    // This alias always diverges but we don't emit an error because
+    // the compiler can't "see" that.
+    type DivergingAssoc<U: Trait> = <U as Trait>::DivergingAssoc<U>;
+}
+```
+
+Ultimately this means that we have no guarantee that aliases in the type system are non-diverging. As aliases may only diverge for some specific generic arguments, it also means that we only know whether an alias diverges once it is fully concrete. This means that codegen/const-evaluation also has to handle diverging aliases:
+```rust
+trait Trait {
+    type Diverges<U: Trait>;
+}
+impl<T: ?Sized> Trait for T {
+    type Diverges<U: Trait> = <U as Trait>::Diverges<U>;
+}
+
+fn foo<T: Trait>() {
+    let a: T::Diverges<T>;
+}
+
+fn main() {
+    foo::<()>();
+}
+```
+In this example we only encounter an error from the diverging alias during codegen of `foo::<()>`, if the call to `foo` is removed then no compilation error will be emitted.
+
+### Opaque Types
+
+Opaque types are a relatively special kind of alias, and are covered in their own chapter: [Opaque types](./opaque-types-type-alias-impl-trait.md).
+
+### Const Aliases
+
+Unlike type aliases, const aliases are not represented directly in the type system, instead const aliases are always an anonymous body containing a path expression to a const item. This means that the only "const alias" in the type system is an anonymous unevaluated const body.
+
+As such there is no `ConstKind::Alias(AliasCtKind::Projection/Inherent/Free, _)`, instead we only have `ConstKind::Unevaluated` which is used for representing anonymous constants.
+
+```rust
+fn foo<const N: usize>() {}
+
+const FREE_CONST: usize = 1 + 1;
+
+fn bar() {
+    foo::<{ FREE_CONST }>();
+    // The const arg is represented with some anonymous constant:
+    // ```pseudo-rust
+    // const ANON: usize = FREE_CONST; 
+    // foo::<ConstKind::Unevaluated(DefId(ANON), [])>();
+    // ```
+}
+```
+
+This is likely to change as const generics functionality is improved, for example `feature(associated_const_equality)` and `feature(min_generic_const_args)` both require handling const aliases similarly to types (without an anonymous constant wrapping all const args).
+
+## What is Normalization
+
+### Structural vs Deep normalization
+
+There are two forms of normalization, structural (sometimes called *shallow*) and deep. Structural normalization should be thought of as only normalizing the "outermost" part of a type. On the other hand deep normalization will normalize *all* aliases in a type.
+
+In practice structural normalization can result in more than just the outer layer of the type being normalized, but this behaviour should not be relied upon. Unnormalizable non-rigid aliases making use of bound variables (`for<'a>`) cannot be normalized by either kind of normalization. 
+
+As an example: conceptually, structurally normalizing the type `Vec<<u8 as Identity>::Assoc>` would be a no-op, whereas deeply normalizing would give `Vec<u8>`. In practice even structural normalization would give `Vec<u8>`, though, again, this should not be relied upon.
+
+Changing the alias to use bound variables will result in different behaviour; `Vec<for<'a> fn(<&'a u8 as Identity>::Assoc)>` would result in no change when structurally normalized, but would result in `Vec<for<'a> fn(&'a u8)>` when deeply normalized.
+
+### Core normalization logic
+
+Structurally normalizing aliases is a little bit more nuanced than replacing the alias with whatever it is defined as being equal to in its definition; the result of normalizing an alias should either be a rigid type or an inference variable (which will later be inferred to a rigid type). To accomplish this we do two things:
+
+First, when normalizing an ambiguous alias it is normalized to an inference variable instead of leaving it as-is, this has two main effects: 
+- Even though an inference variable is not a rigid type, it will always wind up inferred *to* a rigid type so we ensure that the result of normalization will not need to be normalized again
+- Inference variables are used in all cases where a type is non-rigid, allowing the rest of the compiler to not have to deal with *both* ambiguous aliases *and* inference variables 
+
+Secondly, instead of having normalization directly return the type specified in the definition of the alias, we normalize the type first before returning it[^1]. We do this so that normalization is idempotent/callers do not need to run it in a loop.
+
+```rust
+#![feature(lazy_type_alias)]
+
+type Foo<T: Iterator> = Bar<T>;
+type Bar<T: Iterator> = <T as Iterator>::Item;
+
+fn foo() {
+    let a_: Foo<_>;
+}
+```
+
+In this example:
+- Normalizing `Foo<?x>` would result in `Bar<?x>`, except we want to normalize aliases in the type `Foo` is defined as equal to
+- Normalizing `Bar<?x>` would result in `<?x as Iterator>::Item`, except, again, we want to normalize aliases in the type `Bar` is defined as equal to
+- Normalizing `<?x as Iterator>::Item` results in some new inference variable `?y`, as `<?x as Iterator>::Item` is an ambiguous alias
+- The final result is that normalizing `Foo<?x>` results in `?y`
+
+## How to normalize
+
+When interfacing with the type system it will often be the case that it's necessary to request a type be normalized. There are a number of different entry points to the underlying normalization logic and each entry point should only be used in specific parts of the compiler.
+
+An additional complication is that the compiler is currently undergoing a transition from the old trait solver to the new trait solver. As part of this transition our approach to normalization in the compiler has changed somewhat significantly, resulting in some normalization entry points being "old solver only" slated for removal in the long-term once the new solver has stabilized.
+
+Here is a rough overview of the different entry points to normalization in the compiler:
+- `infcx.at.structurally_normalize`
+- `infcx.at.(deeply_)?normalize`
+- `infcx.query_normalize`
+- `tcx.normalize_erasing_regions`
+- `traits::normalize_with_depth(_to)`
+- `EvalCtxt::structurally_normalize`
+
+### Outside of the trait solver
+
+The [`InferCtxt`][infcx] type exposes the "main" ways to normalize during analysis: [`normalize`][normalize], [`deeply_normalize`][deeply_normalize] and [`structurally_normalize`][structurally_normalize]. These functions are often wrapped and re-exposed on various `InferCtxt` wrapper types, such as [`FnCtxt`][fcx] or [`ObligationCtxt`][ocx] with minor API tweaks to handle some arguments or parts of the return type automatically.
+
+#### Structural `InferCtxt` normalization
+
+[`infcx.at.structurally_normalize`][structurally_normalize] exposes structural normalization that is able to handle inference variables and regions. It should generally be used whenever inspecting the kind of a type.
+
+Inside of HIR Typeck there is a related method of normalization- [`fcx.structurally_resolve`][structurally_resolve], which will error if the type being resolved is an unresolved inference variable. When the new solver is enabled it will also attempt to structurally normalize the type.
+
+Due to this there is a pattern in HIR typeck where a type is first normalized via `normalize` (only normalizing in the old solver), and then `structurally_resolve`'d (only normalizing in the new solver). This pattern should be preferred over calling `structurally_normalize` during HIR typeck as `structurally_resolve` will attempt to make inference progress by evaluating goals whereas `structurally_normalize` does not.
+
+#### Deep `InferCtxt` normalization
+
+##### `infcx.at.(deeply_)?normalize`
+
+There are two ways to deeply normalize with an `InferCtxt`, `normalize` and `deeply_normalize`. The reason for this is that `normalize` is a "legacy" normalization entry point used only by the old solver, whereas `deeply_normalize` is intended to be the long term way to deeply normalize. Both of these methods can handle regions.
+
+When the new solver is stabilized the `infcx.at.normalize` function will be removed and everything will have been migrated to the new deep or structural normalization methods. For this reason the `normalize` function is a no-op under the new solver, making it suitable only when the old solver needs normalization but the new solver does not.
+
+Using `deeply_normalize` will result in errors being emitted when encountering ambiguous aliases[^2] as it is not possible to support normalizing *all* ambiguous aliases to inference variables[^3]. `deeply_normalize` should generally only be used in cases where we do not expect to encounter ambiguous aliases, for example when working with types from item signatures.
+
+##### `infcx.query_normalize`
+
+[`infcx.query_normalize`][query_norm] is very rarely used, it has almost all the same restrictions as `normalize_erasing_regions` (cannot handle inference variables, no diagnostics support) with the main difference being that it retains lifetime information. For this reason `normalize_erasing_regions` is the better choice in almost all circumstances as it is more efficient due to caching lifetime-erased queries.
+
+In practice `query_normalize` is used for normalization in the borrow checker, and elsewhere as a performance optimization over `infcx.normalize`. Once the new solver is stabilized it is expected that `query_normalize` can be removed from the compiler as the new solvers normalization implementation should be performant enough for it to not be a performance regression.
+
+##### `tcx.normalize_erasing_regions`
+
+[`normalize_erasing_regions`][norm_erasing_regions] is generally used by parts of the compiler that are not doing type system analysis. This normalization entry point does not handle inference variables, lifetimes, or any diagnostics. Lints and codegen make heavy use of this entry point as they typically are working with fully inferred aliases that can be assumed to be well formed (or at least, are not responsible for erroring on). 
+
+[query_norm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.query_normalize
+[norm_erasing_regions]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.normalize_erasing_regions
+[normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
+[deeply_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/trait.NormalizeExt.html#tymethod.deeply_normalize
+[structurally_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/trait.StructurallyNormalizeExt.html#tymethod.structurally_normalize_ty
+[infcx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/struct.InferCtxt.html
+[fcx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
+[ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
+[structurally_resolve]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.structurally_resolve_type
+
+### Inside of the trait solver
+
+[`traits::normalize_with_depth(_to)`][norm_with_depth] and [`EvalCtxt::structurally_normalize`][eval_ctxt_structural_norm] are only used by the internals of the trait solvers (old and new respectively). It is effectively a raw entry point to the internals of how normalization is implemented by each trait solver. Other normalization entry points cannot be used from within the internals of trait solving as it wouldn't handle goal cycles and recursion depth correctly.
+
+[norm_with_depth]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/fn.normalize_with_depth.html
+[eval_ctxt_structural_norm]:  https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/struct.EvalCtxt.html#method.structurally_normalize_term
+
+## When/Where to normalize (Old vs New solver)
+
+One of the big changes between the old and new solver is our approach to when we expect aliases to be normalized.
+
+### Old solver
+
+All types are expected to be normalized as soon as possible, so that all types encountered in the type system are either rigid or an inference variable (which will later be inferred to a rigid term). 
+
+As a concrete example: equality of aliases is implemented by assuming they're rigid and recursively equating the generic arguments of the alias.
+
+### New solver
+
+It's expected that all types potentially contain ambiguous or unnormalized aliases. Whenever an operation is performed that requires aliases to be normalized, it's the responsibility of that logic to normalize the alias (this means that matching on `ty.kind()` pretty much always has to structurally normalize first).
+
+As a concrete example: equality of aliases is implemented by a custom goal kind ([`PredicateKind::AliasRelate`][aliasrelate]) so that it can handle normalization of the aliases itself instead of assuming all alias types being equated are rigid.
+
+Despite this approach we still deeply normalize during [writeback][writeback] for performance/simplicity, so that types in the MIR can still be assumed to have been deeply normalized. 
+
+[aliasrelate]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.PredicateKind.html#variant.AliasRelate
+[writeback]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/writeback/index.html
+
+---
+
+There were a few main issues with the old solver's approach to normalization that motivated changing things in the new solver:
+
+### Missing normalization calls
+
+It was a frequent occurrence that normalization calls would be missing, resulting in passing unnormalized types to APIs expecting everything to already be normalized. Treating ambiguous or unnormalized aliases as rigid would result in all sorts of weird errors from aliases not being considered equal to one another, or surprising inference guidance from equating unnormalized aliases' generic arguments.
+
+### Normalizing parameter environments
+
+Another problem was that it was not possible to normalize `ParamEnv`s correctly in the old solver as normalization itself would expect a normalized `ParamEnv` in order to give correct results. See the chapter on `ParamEnv`s for more information: [`Typing/ParamEnv`s: Normalizing all bounds](./typing_parameter_envs.md#normalizing-all-bounds)
+
+### Unnormalizable non-rigid aliases in higher ranked types
+
+Given a type such as `for<'a> fn(<?x as Trait<'a>::Assoc>)`, it is not possible to correctly handle this with the old solver's approach to normalization.
+
+If we were to normalize it to `for<'a> fn(?y)` and register a goal to normalize `for<'a> <?x as Trait<'a>>::Assoc -> ?y`, this would result in errors in cases where `<?x as Trait<'a>>::Assoc` normalized to `&'a u32`. The inference variable `?y` would be in a lower [universe][universes] than the placeholders made when instantiating the `for<'a>` binder.
+
+Leaving the alias unnormalized would also be wrong as the old solver expects all aliases to be rigid. This was a soundness bug before the new solver was stabilized in coherence: [relating projection substs is unsound during coherence](https://github.com/rust-lang/rust/issues/102048).
+
+Ultimately this means that it is not always possible to ensure all aliases inside of a value are rigid.
+
+[universes]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html#what-is-a-universe
+[deeply_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/trait.NormalizeExt.html#tymethod.deeply_normalize
+
+## Handling uses of diverging aliases
+
+Diverging aliases, like ambiguous aliases, are normalized to inference variables. As normalizing diverging aliases results in trait solver cycles, it always results in an error in the old solver. In the new solver it only results in an error if we wind up requiring all goals to hold in the current context. E.g. normalizing diverging aliases during HIR typeck will result in an error in both solvers.
+
+Alias well formedness doesn't require that the alias doesn't diverge[^4], this means that checking an alias is well formed isn't sufficient to cause an error to be emitted for diverging aliases; actually attempting to normalize the alias is required.
+
+Erroring on diverging aliases being a side effect of normalization means that it is very *arbitrary* whether we actually emit an error, it also differs between the old and new solver as we now normalize in less places.
+
+An example of the ad-hoc nature of erroring on diverging aliases causing "problems":
+```rust
+trait Trait {
+    type Diverges<D: Trait>;
+}
+
+impl<T> Trait for T {
+    type Diverges<D: Trait> = D::Diverges<D>;
+}
+
+struct Bar<T: ?Sized = <u8 as Trait>::Diverges<u8>>(Box<T>);
+```
+
+In this example a diverging alias is used but we happen to not emit an error as we never explicitly normalize the defaults of generic parameters. If the `?Sized` opt out is removed then an error is emitted because we wind up happening to normalize a `<u8 as Trait>::Diverges<u8>: Sized` goal which as a side effect results in erroring about the diverging alias.
+
+Const aliases differ from type aliases a bit here; well formedness of const aliases requires that they can be successfully evaluated (via [`ConstEvaluatable`][const_evaluatable] goals). This means that simply checking well formedness of const arguments is sufficient to error if they would fail to evaluate. It is somewhat unclear whether it would make sense to adopt this for type aliases too or if const aliases should stop requiring this for well formedness[^5].
+
+[^1]: In the new solver this is done implicitly
+
+[^2]: There is a subtle difference in how ambiguous aliases in binders are handled between old and new solver. In the old solver we fail to error on some ambiguous aliases inside of higher ranked types whereas the new solver correctly errors.
+
+[^3]: Ambiguous aliases inside of binders cannot be normalized to inference variables, this will be covered more later.
+
+[^4]: As checking aliases are non-diverging cannot be done until they are fully concrete, this would either imply that we cant check aliases are well formed before codegen/const-evaluation or that aliases would go from being well-formed to not well-formed after monomorphization.
+
+[^5]: Const aliases certainly wouldn't be *less* sound than type aliases if we stopped doing this
+
+[const_evaluatable]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstEvaluatable
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
index 9ba4eff629e..696f2038e1a 100644
--- a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
+++ b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md
@@ -1,9 +1,9 @@
 # Rust for Linux notification group
 
-**Github Label:** [O-rfl] <br>
+**Github Label:** [A-rust-for-linux] <br>
 **Ping command:** `@rustbot ping rfl`
 
-[O-rfl]: https://github.com/rust-lang/rust/labels/O-rfl
+[A-rust-for-linux]: https://github.com/rust-lang/rust/labels/A-rust-for-linux
 
 This list will be used to notify [Rust for Linux (RfL)][rfl] maintainers
 when the compiler or the standard library changes in a way that would
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
index 7f1c83e00f9..80421b85bf0 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md
@@ -55,8 +55,8 @@ The first step in [`clean::utils::krate`][ck1] is to invoke
   * inlining public `use` exports of private items, or showing a "Reexport"
     line in the module page
   * inlining items with `#[doc(hidden)]` if the base item is hidden but the
-  * showing `#[macro_export]`-ed macros at the crate root, regardless of where
-    they're defined reexport is not
+  * showing `#[macro_export]`-ed macros at the crate root, regardless of whether
+    they're defined as a reexport or not
 
 After this step, `clean::krate` invokes [`clean_doc_module`], which actually
 converts the `HIR` items to the cleaned [`AST`][ast]. This is also the step where cross-
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
index 169b95a7e1a..bad7ac19da2 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
@@ -16,10 +16,10 @@ In addition to the directives listed here,
 `rustdoc` tests also support most
 [compiletest directives](../tests/directives.html).
 
-All `PATH`s in directives are relative to the the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`),
+All `PATH`s in directives are relative to the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`),
 so it is conventional to use a `#![crate_name = "foo"]` attribute to avoid
 having to write a long crate name multiple times.
-To avoid repetion, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument.
+To avoid repetition, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument.
 
 All arguments take the form of quoted strings
 (both single and double quotes are supported),
@@ -87,7 +87,7 @@ compiletest's `--bless` flag is forwarded to htmldocck.
 
 Usage: `//@ has-dir PATH`
 
-Checks for the existance of directory `PATH`.
+Checks for the existence of directory `PATH`.
 
 ### `files`
 
@@ -106,7 +106,7 @@ Example: `//@ files "foo/bar" '["index.html", "sidebar-items.js"]'`
 ## Limitations
 `htmldocck.py` uses the xpath implementation from the standard library.
 This leads to several limitations:
-* All `XPATH` arguments must start with `//` due to a flaw in the implemention.
+* All `XPATH` arguments must start with `//` due to a flaw in the implementation.
 * Many XPath features (functions, axies, etc.) are not supported.
 * Only well-formed HTML can be parsed (hopefully rustdoc doesn't output mismatched tags).
 
diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md
index 670a37ffb0a..47667061eda 100644
--- a/src/doc/rustc-dev-guide/src/serialization.md
+++ b/src/doc/rustc-dev-guide/src/serialization.md
@@ -169,7 +169,7 @@ The `LazyArray<[T]>` and `LazyTable<I, T>` types provide some functionality over
   than the one being read.
 
 **note**: `LazyValue<T>` does not cache its value after being deserialized the
-first time. Instead the query system its self is the main way of caching these
+first time. Instead the query system itself is the main way of caching these
 results.
 
 [`LazyArray<T>`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/struct.LazyValue.html
diff --git a/src/doc/rustc-dev-guide/src/solve/normalization.md b/src/doc/rustc-dev-guide/src/solve/normalization.md
deleted file mode 100644
index 99dc20c46b5..00000000000
--- a/src/doc/rustc-dev-guide/src/solve/normalization.md
+++ /dev/null
@@ -1,127 +0,0 @@
-# Normalization in the new solver
-
-> FIXME: Normalization has been changed significantly since this chapter was written.
-
-With the new solver we've made some fairly significant changes to normalization when compared
-to the existing implementation.
-
-We now differentiate between "one-step normalization", "structural normalization" and
-"deep normalization".
-
-## One-step normalization
-
-One-step normalization is implemented via `NormalizesTo` goals. Unlike other goals
-in the trait solver, `NormalizesTo` always expects the term to be an unconstrained
-inference variable[^opaques]. Think of it as a function, taking an alias as input
-and returning its underlying value. If the alias is rigid, `NormalizesTo` fails and
-returns `NoSolution`. This is the case for `<T as Trait>::Assoc` if there's a `T: Trait`
-where-bound and for opaque types with `Reveal::UserFacing` unless they are in the
-defining scope. We must not treat any aliases as rigid in coherence.
-
-The underlying value may itself be an unnormalized alias, e.g.
-`NormalizesTo(<<() as Id>::This as Id>::This)` only returns `<() as Id>::This`,
-even though that alias can be further normalized to `()`. As the term is
-always an unconstrained inference variable, the expected term cannot influence
-normalization, see [trait-system-refactor-initiative#22] for more.
-
-Only ever computing `NormalizesTo` goals with an unconstrained inference variable
-requires special solver support. It is only used by `AliasRelate` goals and pending
-`NormalizesTo` goals are tracked separately from other goals: [source][try-eval-norm].
-As the expected term is always erased in `NormalizesTo`, we have to return its
-ambiguous nested goals to its caller as not doing so weakens inference. See
-[#122687] for more details.  
-
-[trait-system-refactor-initiative#22]: https://github.com/rust-lang/trait-system-refactor-initiative/issues/22
-[try-eval-norm]: https://github.com/rust-lang/rust/blob/2627e9f3012a97d3136b3e11bf6bd0853c38a534/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs#L523-L537
-[#122687]: https://github.com/rust-lang/rust/pull/122687
-
-## `AliasRelate` and structural normalization
-
-We structurally normalize an alias by applying one-step normalization until
-we end up with a rigid alias, ambiguity, or overflow. This is done by repeatedly
-evaluating `NormalizesTo` goals inside of a snapshot: [source][structural_norm].
-
-`AliasRelate(lhs, rhs)` is implemented by first structurally normalizing both the
-`lhs` and the `rhs` and then relating the resulting rigid types (or inference
-variables). Importantly, if `lhs` or `rhs` ends up as an alias, this alias can
-now be treated as rigid and gets unified without emitting a nested `AliasRelate`
-goal: [source][structural-relate].
-
-This means that `AliasRelate` with an unconstrained `rhs` ends up functioning
-similar to `NormalizesTo`, acting as a function which fully normalizes `lhs`
-before assigning the resulting rigid type to an inference variable. This is used by
-`fn structurally_normalize_ty` both [inside] and [outside] of the trait solver.
-This has to be used whenever we match on the value of some type, both inside
-and outside of the trait solver.
-
-<!--
-FIXME: structure, maybe we should have an "alias handling" chapter instead as
-talking about normalization without explaining that doesn't make too much
-sense.
-
-FIXME: it is likely that this will subtly change again by mostly moving structural
-normalization into `NormalizesTo`.
--->
-
-[structural_norm]: https://github.com/rust-lang/rust/blob/2627e9f3012a97d3136b3e11bf6bd0853c38a534/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L140-L175
-[structural-relate]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L88-L107
-[inside]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/solve/mod.rs#L278-L299
-[outside]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/traits/structural_normalize.rs#L17-L48
-
-## Deep normalization
-
-By walking over a type, and using `fn structurally_normalize_ty` for each encountered
-alias, it is possible to deeply normalize a type, normalizing all aliases as much as
-possible. However, this only works for aliases referencing bound variables if they are
-not ambiguous as we're unable to replace the alias with a corresponding inference
-variable without leaking universes.
-
-<!--
-FIXME: we previously had to also be careful about instantiating the new inference
-variable with another normalizeable alias. Due to our recent changes to generalization,
-this should not be the case anymore. Equating an inference variable with an alias
-now always uses `AliasRelate` to fully normalize the alias before instantiating the
-inference variable: [source][generalize-no-alias]
--->
-
-[generalize-no-alias]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_infer/src/infer/relate/generalize.rs#L353-L358
-
-## Outside of the trait solver
-
-The core type system - relating types and trait solving - will not need deep
-normalization with the new solver. There are still some areas which depend on it.
-For these areas there is the function `At::deeply_normalize`. Without additional
-trait solver support deep normalization does not always work in case of ambiguity.
-Luckily deep normalization is currently only necessary in places where there is no ambiguity.
-`At::deeply_normalize` immediately fails if there's ambiguity.
-
-If we only care about the outermost layer of types, we instead use
-`At::structurally_normalize` or `FnCtxt::(try_)structurally_resolve_type`.
-Unlike `At::deeply_normalize`, structural normalization is also used in cases where we
-have to handle ambiguity.
-
-Because this may result in behavior changes depending on how the trait solver handles
-ambiguity, it is safer to also require full normalization there. This happens in
-`FnCtxt::structurally_resolve_type` which always emits a hard error if the self type ends
-up as an inference variable. There are some existing places which have a fallback for
-inference variables instead. These places use `try_structurally_resolve_type` instead.
-
-## Why deep normalization with ambiguity is hard
-
-Fully correct deep normalization is very challenging, especially with the new solver 
-given that we do not want to deeply normalize inside of the solver. Mostly deeply normalizing
-but sometimes failing to do so is bound to cause very hard to minimize and understand bugs.
-If possible, avoiding any reliance on deep normalization entirely therefore feels preferable.
-
-If the solver itself does not deeply normalize, any inference constraints returned by the
-solver would require normalization. Handling this correctly is ugly. This also means that
-we change goals we provide to the trait solver by "normalizing away" some projections.
-
-The way we (mostly) guarantee deep normalization with the old solver is by eagerly replacing
-the projection with an inference variable and emitting a nested `Projection` goal. This works
-as `Projection` goals in the old solver deeply normalize. Unless we add another `PredicateKind`
-for deep normalization to the new solver we cannot emulate this behavior. This does not work
-for projections with bound variables, sometimes leaving them unnormalized. An approach which
-also supports projections with bound variables will be even more involved. 
-
-[^opaques]: opaque types are currently handled a bit differently. this may change in the future
diff --git a/src/doc/rustc-dev-guide/src/solve/significant-changes.md b/src/doc/rustc-dev-guide/src/solve/significant-changes.md
index c82b5d46896..eac8f0318fb 100644
--- a/src/doc/rustc-dev-guide/src/solve/significant-changes.md
+++ b/src/doc/rustc-dev-guide/src/solve/significant-changes.md
@@ -106,4 +106,4 @@ their ambiguous nested goals are returned to the caller which then evaluates the
 See [#122687] for more details.
 
 [#122687]: https://github.com/rust-lang/rust/pull/122687
-[normalization]: ./normalization.md
+[normalization]: ../normalization.md
diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md
index 2bdc7f3a243..be00207e3fb 100644
--- a/src/doc/rustc-dev-guide/src/tests/best-practices.md
+++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md
@@ -70,6 +70,11 @@ related tests.
 > //!
 > //! Regression test for <https://github.com/rust-lang/rust/issues/123456>.
 > ```
+>
+> One exception to this rule is [crashes tests]: there it is canonical that
+> tests are named only after issue numbers because its purpose is to track
+> snippets from which issues no longer ICE/crash, and they would either be
+> removed or converted into proper ui/other tests in the fix PRs.
 
 ## Test organization
 
@@ -194,3 +199,4 @@ See [LLVM FileCheck guide][FileCheck] for details.
 [compiletest directives]: ./directives.md
 [`run-make`]: ./compiletest.md#run-make-tests
 [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html
+[crashes tests]: ./compiletest.md#crashes-tests
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index c04f296ba0b..825be11c82a 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -135,12 +135,16 @@ There are several use-cases for try builds:
 - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it
   passes the test suite executed by that job.
 
-You can select which CI jobs will
-be executed in the try build by adding lines containing `try-job:
-<job pattern>` to the PR description. All such specified jobs will be executed
-in the try build once the `@bors try` command is used on the PR. If no try
-jobs are specified in this way, the jobs defined in the `try` section of
-[`jobs.yml`] will be executed by default.
+By default, if you send a comment with `@bors try`, the jobs defined in the `try` section of
+[`jobs.yml`] will be executed. We call this mode a "fast try build". Such a try build
+will not execute any tests, and it will allow compilation warnings. It is useful when you want to
+get an optimized toolchain as fast as possible, for a crater run or performance benchmarks,
+even if it might not be working fully correctly.
+
+If you want to run a custom CI job in a try build and make sure that it passes all tests and does
+not produce any compilation warnings, you can select CI jobs to be executed by adding lines
+containing `try-job: <job pattern>` to the PR description. All such specified jobs will be executed
+in the try build once the `@bors try` command is used on the PR.
 
 Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs,
 for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 2c35381eadf..0ba078f0b49 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -325,12 +325,8 @@ The tests in [`tests/codegen-units`] test the
 [monomorphization](../backend/monomorph.md) collector and CGU partitioning.
 
 These tests work by running `rustc` with a flag to print the result of the
-monomorphization collection pass, and then special annotations in the file are
-used to compare against that.
-
-Each test should be annotated with the `//@
-compile-flags:-Zprint-mono-items=VAL` directive with the appropriate `VAL` to
-instruct `rustc` to print the monomorphization information.
+monomorphization collection pass, i.e., `-Zprint-mono-items`, and then special
+annotations in the file are used to compare against that.
 
 Then, the test should be annotated with comments of the form `//~ MONO_ITEM
 name` where `name` is the monomorphized string printed by rustc like `fn <u32 as
diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md
index 7bf30b106b4..c55d60f4a5c 100644
--- a/src/doc/rustc-dev-guide/src/tests/intro.md
+++ b/src/doc/rustc-dev-guide/src/tests/intro.md
@@ -102,11 +102,12 @@ by passing a path to a book to `./x test`.
 
 ### Documentation link checker
 
-Links across all documentation is validated with a link checker tool.
+Links across all documentation is validated with a link checker tool,
+and it can be invoked so:
 
-> Example: `./x test src/tools/linkchecker`
-
-> Example: `./x test linkchecker`
+```console
+./x test linkchecker
+```
 
 This requires building all of the documentation, which might take a while.
 
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index b31c861c947..721d20b65c5 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -344,8 +344,7 @@ For checking runtime output, `//@ check-run-results` may be preferable.
 
 Only use `error-pattern` if none of the above works.
 
-Line annotations `//~` are still checked in tests using `error-pattern`.
-In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks.
+Line annotations `//~` and `error-pattern` are compatible and can be used in the same test.
 
 ### Diagnostic kinds (error levels)
 
@@ -356,9 +355,12 @@ The diagnostic kinds that you can have are:
 - `NOTE`
 - `HELP`
 - `SUGGESTION`
+- `RAW`
 
 The `SUGGESTION` kind is used for specifying what the expected replacement text
 should be for a diagnostic suggestion.
+The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted
+by the compiler instead of or in addition to structured json.
 
 `ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
 `//~` by default.
diff --git a/src/doc/rustc-dev-guide/src/traits/unsize.md b/src/doc/rustc-dev-guide/src/traits/unsize.md
index dd57a1b0796..98a44525748 100644
--- a/src/doc/rustc-dev-guide/src/traits/unsize.md
+++ b/src/doc/rustc-dev-guide/src/traits/unsize.md
@@ -32,21 +32,21 @@ Built-in implementations are provided for:
 
 ## Structural implementations
 
-There are two implementations of `Unsize` which can be thought of as
+There is one implementation of `Unsize` which can be thought of as
 structural:
-* `(A1, A2, .., An): Unsize<(A1, A2, .., U)>` given `An: Unsize<U>`, which
-  allows the tail field of a tuple to be unsized. This is gated behind the
-  [`unsized_tuple_coercion`] feature.
 * `Struct<.., Pi, .., Pj, ..>: Unsize<Struct<.., Ui, .., Uj, ..>>` given 
   `TailField<Pi, .., Pj>: Unsize<Ui, .. Uj>`, which allows the tail field of a
   struct to be unsized if it is the only field that mentions generic parameters
   `Pi`, .., `Pj` (which don't need to be contiguous).
 
-The rules for the latter implementation are slightly complicated, since they
+The rules for struct unsizing are slightly complicated, since they
 may allow more than one parameter to be changed (not necessarily unsized) and
 are best stated in terms of the tail field of the struct.
 
-[`unsized_tuple_coercion`]: https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-tuple-coercion.html
+(Tuple unsizing was previously implemented behind the feature gate
+`unsized_tuple_coercion`, but the implementation was removed by [#137728].)
+
+[#137728]: https://github.com/rust-lang/rust/pull/137728
 
 ## Upcasting implementations
 
diff --git a/src/doc/rustc-dev-guide/src/ty-fold.md b/src/doc/rustc-dev-guide/src/ty-fold.md
index d4d0952fcc3..23253022ffe 100644
--- a/src/doc/rustc-dev-guide/src/ty-fold.md
+++ b/src/doc/rustc-dev-guide/src/ty-fold.md
@@ -1,26 +1,28 @@
+<!-- date-check: may 2024 -->
 # `TypeFoldable` and `TypeFolder`
 
-In the previous chapter we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder`
-to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary rust type `T` not just a `Ty` so
-how do we implement the `instantiate` methods on the `Early/Binder` types.
+In [a previous chapter], we discussed instantiating binders.
+This involves looking at everything inside of a `Early(Binder)`
+to find any usages of the bound vars in order to replace them.
+Binders can wrap an arbitrary Rust type `T`, not just a `Ty`.
+So, how do we implement the `instantiate` methods on the `Early/Binder` types?
 
 The answer is a couple of traits:
-[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html)
+[`TypeFoldable`]
 and
-[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html).
+[`TypeFolder`].
 
 - `TypeFoldable` is implemented by types that embed type information. It allows you to recursively
   process the contents of the `TypeFoldable` and do stuff to them.
 - `TypeFolder` defines what you want to do with the types you encounter while processing the
   `TypeFoldable`.
 
-For example, the `TypeFolder` trait has a method
-[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html#method.fold_ty)
-that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the
-`TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the
-types, regions, etc that are contained within).
+For example, the `TypeFolder` trait has a method [`fold_ty`]
+that takes a type as input and returns a new type as a result.
+`TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself,
+giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within).
 
-You can think of it with this analogy to the iterator combinators we have come to love in rust:
+You can think of it with this analogy to the iterator combinators we have come to love in Rust:
 
 ```rust,ignore
 vec.iter().map(|e1| foo(e2)).collect()
@@ -33,8 +35,7 @@ So to reiterate:
 - `TypeFolder`  is a trait that defines a “map” operation.
 - `TypeFoldable`  is a trait that is implemented by things that embed types.
 
-In the case of `subst`, we can see that it is implemented as a `TypeFolder`:
-[`ArgFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html).
+In the case of `subst`, we can see that it is implemented as a `TypeFolder`: [`ArgFolder`].
 Looking at its implementation, we see where the actual substitutions are happening.
 
 However, you might also notice that the implementation calls this `super_fold_with` method. What is
@@ -88,17 +89,22 @@ things. We only want to do something when we reach a type. That means there may
 `TypeFoldable` types whose implementations basically just forward to their fields’ `TypeFoldable`
 implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand.
 For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is
-defined
-[here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs).
-
-**`subst`** In the case of substitutions the [actual
-folder](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451)
-is going to be doing the indexing we’ve already mentioned. There we define a `Folder` and call
-`fold_with` on the `TypeFoldable` to process yourself.  Then
-[fold_ty](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536)
-the method that process each type it looks for a `ty::Param` and for those it replaces it for
-something from the list of substitutions, otherwise recursively process the type.  To replace it,
-calls
-[ty_for_param](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587)
+defined [here].
+
+**`subst`** In the case of substitutions the [actual folder]
+is going to be doing the indexing we’ve already mentioned.
+There we define a `Folder` and call `fold_with` on the `TypeFoldable` to process yourself.
+Then [fold_ty] the method that process each type it looks for a `ty::Param` and for those
+it replaces it for something from the list of substitutions, otherwise recursively process the type.
+To replace it, calls [ty_for_param]
 and all that does is index into the list of substitutions with the index of the `Param`.
 
+[a previous chapter]: ty_module/instantiating_binders.md
+[`TypeFoldable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html
+[`TypeFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html
+[`fold_ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty
+[`ArgFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html
+[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs
+[actual folder]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451
+[fold_ty]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536
+[ty_for_param]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587
diff --git a/src/doc/rustc-dev-guide/src/type-checking.md b/src/doc/rustc-dev-guide/src/type-checking.md
index b60694201f3..4e8b30b19fc 100644
--- a/src/doc/rustc-dev-guide/src/type-checking.md
+++ b/src/doc/rustc-dev-guide/src/type-checking.md
@@ -17,7 +17,7 @@ Type "collection" is the process of converting the types found in the HIR
 **internal representation** used by the compiler (`Ty<'tcx>`) – we also do
 similar conversions for where-clauses and other bits of the function signature.
 
-To try and get a sense for the difference, consider this function:
+To try and get a sense of the difference, consider this function:
 
 ```rust,ignore
 struct Foo { }
diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md
index c03fa36d79d..888eb2439c5 100644
--- a/src/doc/rustc-dev-guide/src/type-inference.md
+++ b/src/doc/rustc-dev-guide/src/type-inference.md
@@ -19,7 +19,7 @@ Here, the type of `things` is *inferred* to be `Vec<&str>` because of the value
 we push into `things`.
 
 The type inference is based on the standard Hindley-Milner (HM) type inference
-algorithm, but extended in various way to accommodate subtyping, region
+algorithm, but extended in various ways to accommodate subtyping, region
 inference, and higher-ranked types.
 
 ## A note on terminology
diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
index 757296d1f65..67eaf51bf29 100644
--- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
+++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md
@@ -4,7 +4,7 @@
 
 ## Typing Environments
 
-When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The the set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
+When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
 
 When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type.
 
@@ -13,11 +13,11 @@ Once a context to perform type system operations in has been created (e.g. an [`
 [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
 [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
 
-## Parameter Environemnts
+## Parameter Environments
 
 ### What is a `ParamEnv`
 
-The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead are implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds.
+The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds.
 
 In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses.
 
@@ -73,7 +73,7 @@ fn foo2<T>(a: T) {
 
 ### Acquiring a `ParamEnv`
 
-Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroing when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
+Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroring when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
 
 In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`:
 - During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env]
diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml
index 6232dbf05fd..53fa72469fd 100644
--- a/src/doc/rustc-dev-guide/triagebot.toml
+++ b/src/doc/rustc-dev-guide/triagebot.toml
@@ -13,3 +13,6 @@ allow-unauthenticated = [
 
 # Automatically close and reopen PRs made by bots to run CI on them
 [bot-pull-requests]
+
+[behind-upstream]
+days-threshold = 7
\ No newline at end of file
diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml
index 167aece0ed6..01f127ad390 100644
--- a/src/doc/rustc/book.toml
+++ b/src/doc/rustc/book.toml
@@ -6,6 +6,8 @@ title = "The rustc book"
 [output.html]
 git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
 edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
+additional-css = ["theme/pagetoc.css"]
+additional-js = ["theme/pagetoc.js"]
 
 [output.html.search]
 use-boolean-and = true
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index cf41f5b86a8..a3939e5a5c4 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -58,6 +58,7 @@
       - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md)
       - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
       - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
+    - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 50c7ae3ef8d..60002a5f9e5 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -156,7 +156,7 @@ target | std | notes
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
 [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
 [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
-`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
+[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
 `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27)
diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
new file mode 100644
index 00000000000..1baf1049994
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
@@ -0,0 +1,29 @@
+# `armv5te-unknown-linux-gnueabi`
+
+**Tier: 2**
+
+This target supports Linux programs with glibc on ARMv5TE CPUs without
+floating-point units.
+
+## Target maintainers
+
+[@koalatux](https://github.com/koalatux)
+
+## Requirements
+
+The target is for cross-compilation only. Host tools are not supported.
+std is fully supported.
+
+## Building the target
+
+Because this target is tier 2, artifacts are available from rustup.
+
+## Building Rust programs
+
+For building rust programs, you might want to specify GCC as linker in
+`.cargo/config.toml` as follows:
+
+```toml
+[target.armv5te-unknown-linux-gnueabi]
+linker = "arm-linux-gnueabi-gcc"
+```
diff --git a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
index 09b42da26e7..1d02a7cfbc0 100644
--- a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
@@ -8,7 +8,6 @@ RISC Zero's Zero Knowledge Virtual Machine (zkVM) implementing the RV32IM instru
 
 [@flaub](https://github.com/flaub)
 [@jbruestle](https://github.com/jbruestle)
-[@SchmErik](https://github.com/SchmErik)
 
 ## Background
 
diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md
index 1189d27c95d..994b3adb92e 100644
--- a/src/doc/rustc/src/platform-support/xtensa.md
+++ b/src/doc/rustc/src/platform-support/xtensa.md
@@ -24,4 +24,4 @@ Xtensa targets that support `std` are documented in the [ESP-IDF platform suppor
 
 ## Building the targets
 
-The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of the The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html).
+The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html).
diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css
new file mode 100644
index 00000000000..58ca1f8b26f
--- /dev/null
+++ b/src/doc/rustc/theme/pagetoc.css
@@ -0,0 +1,84 @@
+/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */
+
+:root {
+    --toc-width: 270px;
+    --center-content-toc-shift: calc(-1 * var(--toc-width) / 2);
+}
+
+.nav-chapters {
+    /* adjust width of buttons that bring to the previous or the next page */
+    min-width: 50px;
+}
+
+@media only screen {
+    @media (max-width: 1179px) {
+        .sidebar-hidden #sidetoc {
+            display: none;
+        }
+    }
+
+    @media (max-width: 1439px) {
+        .sidebar-visible #sidetoc {
+            display: none;
+        }
+    }
+
+    @media (1180px <= width <= 1439px) {
+        .sidebar-hidden main {
+            position: relative;
+            left: var(--center-content-toc-shift);
+        }
+    }
+
+    @media (1440px <= width <= 1700px) {
+        .sidebar-visible main {
+            position: relative;
+            left: var(--center-content-toc-shift);
+        }
+    }
+
+    #sidetoc {
+        margin-left: calc(100% + 20px);
+    }
+    #pagetoc {
+        position: fixed;
+        /* adjust TOC width */
+        width: var(--toc-width);
+        height: calc(100vh - var(--menu-bar-height) - 0.67em * 4);
+        overflow: auto;
+    }
+    #pagetoc a {
+        border-left: 1px solid var(--sidebar-bg);
+        color: var(--sidebar-fg) !important;
+        display: block;
+        padding-bottom: 5px;
+        padding-top: 5px;
+        padding-left: 10px;
+        text-align: left;
+        text-decoration: none;
+    }
+    #pagetoc a:hover,
+    #pagetoc a.active {
+        background: var(--sidebar-bg);
+        color: var(--sidebar-active) !important;
+    }
+    #pagetoc .active {
+        background: var(--sidebar-bg);
+        color: var(--sidebar-active);
+    }
+    #pagetoc .pagetoc-H2 {
+        padding-left: 20px;
+    }
+    #pagetoc .pagetoc-H3 {
+        padding-left: 40px;
+    }
+    #pagetoc .pagetoc-H4 {
+        padding-left: 60px;
+    }
+}
+
+@media print {
+    #sidetoc {
+        display: none;
+    }
+}
diff --git a/src/doc/rustc/theme/pagetoc.js b/src/doc/rustc/theme/pagetoc.js
new file mode 100644
index 00000000000..927a5b10749
--- /dev/null
+++ b/src/doc/rustc/theme/pagetoc.js
@@ -0,0 +1,104 @@
+// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL)
+
+let activeHref = location.href;
+function updatePageToc(elem = undefined) {
+    let selectedPageTocElem = elem;
+    const pagetoc = document.getElementById("pagetoc");
+
+    function getRect(element) {
+        return element.getBoundingClientRect();
+    }
+
+    function overflowTop(container, element) {
+        return getRect(container).top - getRect(element).top;
+    }
+
+    function overflowBottom(container, element) {
+        return getRect(container).bottom - getRect(element).bottom;
+    }
+
+    // We've not selected a heading to highlight, and the URL needs updating
+    // so we need to find a heading based on the URL
+    if (selectedPageTocElem === undefined && location.href !== activeHref) {
+        activeHref = location.href;
+        for (const pageTocElement of pagetoc.children) {
+            if (pageTocElement.href === activeHref) {
+                selectedPageTocElem = pageTocElement;
+            }
+        }
+    }
+
+    // We still don't have a selected heading, let's try and find the most
+    // suitable heading based on the scroll position
+    if (selectedPageTocElem === undefined) {
+        const margin = window.innerHeight / 3;
+
+        const headers = document.getElementsByClassName("header");
+        for (let i = 0; i < headers.length; i++) {
+            const header = headers[i];
+            if (selectedPageTocElem === undefined && getRect(header).top >= 0) {
+                if (getRect(header).top < margin) {
+                    selectedPageTocElem = header;
+                } else {
+                    selectedPageTocElem = headers[Math.max(0, i - 1)];
+                }
+            }
+            // a very long last section's heading is over the screen
+            if (selectedPageTocElem === undefined && i === headers.length - 1) {
+                selectedPageTocElem = header;
+            }
+        }
+    }
+
+    // Remove the active flag from all pagetoc elements
+    for (const pageTocElement of pagetoc.children) {
+        pageTocElement.classList.remove("active");
+    }
+
+    // If we have a selected heading, set it to active and scroll to it
+    if (selectedPageTocElem !== undefined) {
+        for (const pageTocElement of pagetoc.children) {
+            if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) {
+                pageTocElement.classList.add("active");
+                if (overflowTop(pagetoc, pageTocElement) > 0) {
+                    pagetoc.scrollTop = pageTocElement.offsetTop;
+                }
+                if (overflowBottom(pagetoc, pageTocElement) < 0) {
+                    pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement);
+                }
+            }
+        }
+    }
+}
+
+if (document.getElementById("sidetoc") === null &&
+    document.getElementsByClassName("header").length > 0) {
+    // The sidetoc element doesn't exist yet, let's create it
+
+    // Create the empty sidetoc and pagetoc elements
+    const sidetoc = document.createElement("div");
+    const pagetoc = document.createElement("div");
+    sidetoc.id = "sidetoc";
+    pagetoc.id = "pagetoc";
+    sidetoc.appendChild(pagetoc);
+
+    // And append them to the current DOM
+    const main = document.querySelector('main');
+    main.insertBefore(sidetoc, main.firstChild);
+
+    // Populate sidebar on load
+    window.addEventListener("load", () => {
+        for (const header of document.getElementsByClassName("header")) {
+            const link = document.createElement("a");
+            link.innerHTML = header.innerHTML;
+            link.href = header.hash;
+            link.classList.add("pagetoc-" + header.parentElement.tagName);
+            document.getElementById("pagetoc").appendChild(link);
+            link.onclick = () => updatePageToc(link);
+        }
+        updatePageToc();
+    });
+
+    // Update page table of contents selected heading on scroll
+    window.addEventListener("scroll", () => updatePageToc());
+}
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index 077b02d603d..e6b15e0dbd3 100644
--- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -462,7 +462,7 @@ struct Foo;
 ```
 
 In older versions, this will be ignored on all targets, but starting with
-version CURRENT_RUSTC_VERSION, `ignore-x86_64` will override `ignore`.
+version 1.88.0, `ignore-x86_64` will override `ignore`.
 
 ### Custom CSS classes for code blocks
 
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index 19e62c4867c..81b7ff50052 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -26,6 +26,10 @@ edition).
 Not all Rust editions have corresponding changes to the Rust style. For
 instance, Rust 2015, Rust 2018, and Rust 2021 all use the same style edition.
 
+## Rust next style edition
+
+- Never break within a nullary function call `func()` or a unit literal `()`.
+
 ## Rust 2024 style edition
 
 This style guide describes the Rust 2024 style edition. The Rust 2024 style
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 031e59d86e1..9df5d7d18ed 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -183,6 +183,10 @@ let f = Foo {
 };
 ```
 
+## Unit literals
+
+Never break between the opening and closing parentheses of the `()` unit literal.
+
 ## Tuple literals
 
 Use a single-line form where possible. Do not put spaces between the opening
@@ -377,6 +381,11 @@ Do put a space between an argument, and the comma which precedes it.
 
 Prefer not to break a line in the callee expression.
 
+For a function call with no arguments (a nullary function call like `func()`),
+never break within the parentheses, and never put a space between the
+parentheses. Always write a nullary function call as a single-line call, never
+a multi-line call.
+
 ### Single-line calls
 
 Do not put a space between the function name and open paren, between the open
diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md
index d870edf1888..66e7fa3c9f8 100644
--- a/src/doc/style-guide/src/nightly.md
+++ b/src/doc/style-guide/src/nightly.md
@@ -5,15 +5,3 @@ This chapter documents style and formatting for nightly-only syntax. The rest of
 Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization.
 
 There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter.
-
-### `feature(precise_capturing)`
-
-A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`.
-
-```
-fn foo() -> impl Sized + use<'a> {}
-
-// is formatted analogously to:
-
-fn foo() -> impl Sized + Use<'a> {}
-```
diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md
index b7921c8914e..247f05b5769 100644
--- a/src/doc/style-guide/src/types.md
+++ b/src/doc/style-guide/src/types.md
@@ -59,3 +59,15 @@ Box<
     + Debug
 >
 ```
+
+## Precise capturing bounds
+
+A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`.
+
+```rust
+fn foo() -> impl Sized + use<'a> {}
+
+// is formatted analogously to:
+
+fn foo() -> impl Sized + Use<'a> {}
+```
diff --git a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md
index 2f8b52d4043..d660dd13fe4 100644
--- a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md
+++ b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md
@@ -2,7 +2,7 @@
 
 The tracking issue for this feature is: [#44874]
 
-[#38788]: https://github.com/rust-lang/rust/issues/44874
+[#44874]: https://github.com/rust-lang/rust/issues/44874
 
 ------------------------
 
diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md
index 0cc7106da48..4c3d456b9af 100644
--- a/src/doc/unstable-book/src/language-features/deref-patterns.md
+++ b/src/doc/unstable-book/src/language-features/deref-patterns.md
@@ -60,20 +60,30 @@ Like [`box_patterns`], deref patterns may move out of boxes:
 # #![feature(deref_patterns)]
 # #![allow(incomplete_features)]
 struct NoCopy;
-// Match exhaustiveness analysis is not yet implemented.
-let deref!(x) = Box::new(NoCopy) else { unreachable!() };
+let deref!(x) = Box::new(NoCopy);
 drop::<NoCopy>(x);
 ```
 
-Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str`
-is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is
-expected. This lets them be used in `deref!(_)` patterns:
+Additionally, `deref_patterns` implements changes to string and byte string literal patterns,
+allowing then to be used in deref patterns:
 
 ```rust
 # #![feature(deref_patterns)]
 # #![allow(incomplete_features)]
-match ("test".to_string(), b"test".to_vec()) {
-    (deref!("test"), deref!(b"test")) => {}
+match ("test".to_string(), Box::from("test"), b"test".to_vec()) {
+    ("test", "test", b"test") => {}
+    _ => panic!(),
+}
+
+// This works through multiple layers of reference and smart pointer:
+match (&Box::new(&"test".to_string()), &&&"test") {
+    ("test", "test") => {}
+    _ => panic!(),
+}
+
+// `deref!("...")` syntax may also be used:
+match "test".to_string() {
+    deref!("test") => {}
     _ => panic!(),
 }
 
@@ -82,10 +92,16 @@ match *"test" {
     "test" => {}
     _ => panic!(),
 }
+match *b"test" {
+    b"test" => {}
+    _ => panic!(),
+}
+match *(b"test" as &[u8]) {
+    b"test" => {}
+    _ => panic!(),
+}
 ```
 
-Implicit deref pattern syntax is not yet supported for string or byte string literals.
-
 [`box_patterns`]: ./box-patterns.md
 [`string_deref_patterns`]: ./string-deref-patterns.md
 [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors
diff --git a/src/doc/unstable-book/src/language-features/f128.md b/src/doc/unstable-book/src/language-features/f128.md
index 0cc5f677230..b523ffe10f2 100644
--- a/src/doc/unstable-book/src/language-features/f128.md
+++ b/src/doc/unstable-book/src/language-features/f128.md
@@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909]
 
 ---
 
-Enable the `f128` type for  IEEE 128-bit floating numbers (quad precision).
+Enable the `f128` type for IEEE 128-bit floating numbers (quad precision).
diff --git a/src/doc/unstable-book/src/language-features/f16.md b/src/doc/unstable-book/src/language-features/f16.md
index efb07a5146d..5f31dcbb06c 100644
--- a/src/doc/unstable-book/src/language-features/f16.md
+++ b/src/doc/unstable-book/src/language-features/f16.md
@@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909]
 
 ---
 
-Enable the `f16` type for  IEEE 16-bit floating numbers (half precision).
+Enable the `f16` type for IEEE 16-bit floating numbers (half precision).
diff --git a/src/doc/unstable-book/src/language-features/frontmatter.md b/src/doc/unstable-book/src/language-features/frontmatter.md
new file mode 100644
index 00000000000..1d5b4feb6ac
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/frontmatter.md
@@ -0,0 +1,25 @@
+# `frontmatter`
+
+The tracking issue for this feature is: [#136889]
+
+------
+
+The `frontmatter` feature allows an extra metadata block at the top of files for consumption by
+external tools. For example, it can be used by [`cargo-script`] files to specify dependencies.
+
+```rust
+#!/usr/bin/env -S cargo -Zscript
+---
+[dependencies]
+libc = "0.2.172"
+---
+#![feature(frontmatter)]
+# mod libc { pub type c_int = i32; }
+
+fn main() {
+    let x: libc::c_int = 1i32;
+}
+```
+
+[#136889]: https://github.com/rust-lang/rust/issues/136889
+[`cargo-script`]: https://rust-lang.github.io/rfcs/3502-cargo-script.html
diff --git a/src/doc/unstable-book/src/library-features/duration-constructors-lite.md b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md
new file mode 100644
index 00000000000..5238b84f776
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md
@@ -0,0 +1,11 @@
+# `duration_constructors_lite`
+
+The tracking issue for this feature is: [#140881]
+
+[#140881]: https://github.com/rust-lang/rust/issues/140881
+
+------------------------
+
+Add the methods `from_mins`, `from_hours` to `Duration`.
+
+For `from_days` and `from_weeks` see [`duration_constructors`](https://github.com/rust-lang/rust/issues/120301).
diff --git a/src/doc/unstable-book/src/library-features/duration-constructors.md b/src/doc/unstable-book/src/library-features/duration-constructors.md
index 098519c7c90..49ad78d1961 100644
--- a/src/doc/unstable-book/src/library-features/duration-constructors.md
+++ b/src/doc/unstable-book/src/library-features/duration-constructors.md
@@ -6,4 +6,5 @@ The tracking issue for this feature is: [#120301]
 
 ------------------------
 
-Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`.
+Add the methods `from_days` and `from_weeks` to `Duration`.
+For `from_mins` and `from_hours` see [duration-constructors-lite.md](./duration-constructors-lite.md)
diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml
index 8a9c5322ef7..e407e322f9e 100644
--- a/src/etc/test-float-parse/Cargo.toml
+++ b/src/etc/test-float-parse/Cargo.toml
@@ -13,3 +13,10 @@ rayon = "1"
 
 [lib]
 name = "test_float_parse"
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    # Internal features aren't marked known config by default
+    'cfg(target_has_reliable_f16)',
+]
diff --git a/src/etc/test-float-parse/src/gen_/subnorm.rs b/src/etc/test-float-parse/src/gen_/subnorm.rs
index 4fe3b90a3dd..654f324b9b0 100644
--- a/src/etc/test-float-parse/src/gen_/subnorm.rs
+++ b/src/etc/test-float-parse/src/gen_/subnorm.rs
@@ -1,4 +1,3 @@
-use std::cmp::min;
 use std::fmt::Write;
 use std::ops::RangeInclusive;
 
@@ -83,7 +82,13 @@ where
     }
 
     fn new() -> Self {
-        Self { iter: F::Int::ZERO..=min(F::Int::ONE << 22, F::MAN_BITS.try_into().unwrap()) }
+        let upper_lim = if F::MAN_BITS >= 22 {
+            F::Int::ONE << 22
+        } else {
+            (F::Int::ONE << F::MAN_BITS) - F::Int::ONE
+        };
+
+        Self { iter: F::Int::ZERO..=upper_lim }
     }
 
     fn write_string(s: &mut String, ctx: Self::WriteCtx) {
diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs
index 3c3ef5802b6..0bd4878f9a6 100644
--- a/src/etc/test-float-parse/src/lib.rs
+++ b/src/etc/test-float-parse/src/lib.rs
@@ -1,3 +1,7 @@
+#![feature(f16)]
+#![feature(cfg_target_has_reliable_f16_f128)]
+#![expect(internal_features)] // reliable_f16_f128
+
 mod traits;
 mod ui;
 mod validate;
@@ -114,6 +118,9 @@ pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
     let mut tests = Vec::new();
 
     // Register normal generators for all floats.
+
+    #[cfg(target_has_reliable_f16)]
+    register_float::<f16>(&mut tests, cfg);
     register_float::<f32>(&mut tests, cfg);
     register_float::<f64>(&mut tests, cfg);
 
diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs
index 57e702b7d09..65a8721bfa5 100644
--- a/src/etc/test-float-parse/src/traits.rs
+++ b/src/etc/test-float-parse/src/traits.rs
@@ -98,7 +98,7 @@ macro_rules! impl_int {
     }
 }
 
-impl_int!(u32, i32; u64, i64);
+impl_int!(u16, i16; u32, i32; u64, i64);
 
 /// Floating point types.
 pub trait Float:
@@ -170,6 +170,9 @@ macro_rules! impl_float {
 
 impl_float!(f32, u32; f64, u64);
 
+#[cfg(target_has_reliable_f16)]
+impl_float!(f16, u16);
+
 /// A test generator. Should provide an iterator that produces unique patterns to parse.
 ///
 /// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to
diff --git a/src/gcc b/src/gcc
-Subproject 0ea98a1365b81f7488073512c850e8ee951a4af
+Subproject 04ce66d8c918de9273bd7101638ad8724edf5e2
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 27ae0553c60..dbfdd8ebd16 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -14,7 +14,6 @@ base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
 minifier = { version = "0.3.5", default-features = false }
-pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 1541e7201ce..439777843fb 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -144,7 +144,7 @@ impl Cfg {
 
     /// Whether the configuration consists of just `Cfg` or `Not`.
     fn is_simple(&self) -> bool {
-        match *self {
+        match self {
             Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true,
             Cfg::All(..) | Cfg::Any(..) => false,
         }
@@ -152,7 +152,7 @@ impl Cfg {
 
     /// Whether the configuration consists of just `Cfg`, `Not` or `All`.
     fn is_all(&self) -> bool {
-        match *self {
+        match self {
             Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true,
             Cfg::Any(..) => false,
         }
@@ -204,7 +204,7 @@ impl Cfg {
     }
 
     fn should_append_only_to_description(&self) -> bool {
-        match *self {
+        match self {
             Cfg::False | Cfg::True => false,
             Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true,
             Cfg::Not(box Cfg::Cfg(..)) => true,
@@ -261,17 +261,17 @@ impl ops::Not for Cfg {
 impl ops::BitAndAssign for Cfg {
     fn bitand_assign(&mut self, other: Cfg) {
         match (self, other) {
-            (&mut Cfg::False, _) | (_, Cfg::True) => {}
+            (Cfg::False, _) | (_, Cfg::True) => {}
             (s, Cfg::False) => *s = Cfg::False,
-            (s @ &mut Cfg::True, b) => *s = b,
-            (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => {
+            (s @ Cfg::True, b) => *s = b,
+            (Cfg::All(a), Cfg::All(ref mut b)) => {
                 for c in b.drain(..) {
                     if !a.contains(&c) {
                         a.push(c);
                     }
                 }
             }
-            (&mut Cfg::All(ref mut a), ref mut b) => {
+            (Cfg::All(a), ref mut b) => {
                 if !a.contains(b) {
                     a.push(mem::replace(b, Cfg::True));
                 }
@@ -305,15 +305,15 @@ impl ops::BitOrAssign for Cfg {
     fn bitor_assign(&mut self, other: Cfg) {
         match (self, other) {
             (Cfg::True, _) | (_, Cfg::False) | (_, Cfg::True) => {}
-            (s @ &mut Cfg::False, b) => *s = b,
-            (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => {
+            (s @ Cfg::False, b) => *s = b,
+            (Cfg::Any(a), Cfg::Any(ref mut b)) => {
                 for c in b.drain(..) {
                     if !a.contains(&c) {
                         a.push(c);
                     }
                 }
             }
-            (&mut Cfg::Any(ref mut a), ref mut b) => {
+            (Cfg::Any(a), ref mut b) => {
                 if !a.contains(b) {
                     a.push(mem::replace(b, Cfg::True));
                 }
@@ -440,40 +440,34 @@ impl Display<'_> {
 
 impl fmt::Display for Display<'_> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self.0 {
-            Cfg::Not(ref child) => match **child {
-                Cfg::Any(ref sub_cfgs) => {
-                    let separator =
-                        if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " };
-                    fmt.write_str("neither ")?;
-
-                    sub_cfgs
-                        .iter()
-                        .map(|sub_cfg| {
-                            fmt::from_fn(|fmt| {
-                                write_with_opt_paren(
-                                    fmt,
-                                    !sub_cfg.is_all(),
-                                    Display(sub_cfg, self.1),
-                                )
-                            })
+        match self.0 {
+            Cfg::Not(box Cfg::Any(sub_cfgs)) => {
+                let separator =
+                    if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " };
+                fmt.write_str("neither ")?;
+
+                sub_cfgs
+                    .iter()
+                    .map(|sub_cfg| {
+                        fmt::from_fn(|fmt| {
+                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
                         })
-                        .joined(separator, fmt)
-                }
-                ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)),
-                ref c => write!(fmt, "not ({})", Display(c, self.1)),
-            },
+                    })
+                    .joined(separator, fmt)
+            }
+            Cfg::Not(box simple @ Cfg::Cfg(..)) => write!(fmt, "non-{}", Display(simple, self.1)),
+            Cfg::Not(box c) => write!(fmt, "not ({})", Display(c, self.1)),
 
-            Cfg::Any(ref sub_cfgs) => {
+            Cfg::Any(sub_cfgs) => {
                 let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " };
                 self.display_sub_cfgs(fmt, sub_cfgs, separator)
             }
-            Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "),
+            Cfg::All(sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "),
 
             Cfg::True => fmt.write_str("everywhere"),
             Cfg::False => fmt.write_str("nowhere"),
 
-            Cfg::Cfg(name, value) => {
+            &Cfg::Cfg(name, value) => {
                 let human_readable = match (name, value) {
                     (sym::unix, None) => "Unix",
                     (sym::windows, None) => "Windows",
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 622a410837b..28dfa01534e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -224,9 +224,9 @@ fn clean_generic_bound<'tcx>(
     bound: &hir::GenericBound<'tcx>,
     cx: &mut DocContext<'tcx>,
 ) -> Option<GenericBound> {
-    Some(match *bound {
+    Some(match bound {
         hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
-        hir::GenericBound::Trait(ref t) => {
+        hir::GenericBound::Trait(t) => {
             // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
             if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
                 && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
@@ -352,8 +352,8 @@ fn clean_where_predicate<'tcx>(
     if !predicate.kind.in_where_clause() {
         return None;
     }
-    Some(match *predicate.kind {
-        hir::WherePredicateKind::BoundPredicate(ref wbp) => {
+    Some(match predicate.kind {
+        hir::WherePredicateKind::BoundPredicate(wbp) => {
             let bound_params = wbp
                 .bound_generic_params
                 .iter()
@@ -366,12 +366,12 @@ fn clean_where_predicate<'tcx>(
             }
         }
 
-        hir::WherePredicateKind::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
+        hir::WherePredicateKind::RegionPredicate(wrp) => WherePredicate::RegionPredicate {
             lifetime: clean_lifetime(wrp.lifetime, cx),
             bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
         },
 
-        hir::WherePredicateKind::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+        hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate {
             lhs: clean_ty(wrp.lhs_ty, cx),
             rhs: clean_ty(wrp.rhs_ty, cx).into(),
         },
@@ -2112,7 +2112,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             );
             Type::Path { path }
         }
-        ty::Dynamic(obj, ref reg, _) => {
+        ty::Dynamic(obj, reg, _) => {
             // HACK: pick the first `did` as the `did` of the trait object. Someone
             // might want to implement "native" support for marker-trait-only
             // trait objects.
@@ -2129,7 +2129,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
             inline::record_extern_fqn(cx, did, ItemType::Trait);
 
-            let lifetime = clean_trait_object_lifetime_bound(*reg, container, obj, cx.tcx);
+            let lifetime = clean_trait_object_lifetime_bound(reg, container, obj, cx.tcx);
 
             let mut bounds = dids
                 .map(|did| {
@@ -2846,7 +2846,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 ));
                 return ret;
             }
-            ItemKind::Enum(_, ref def, generics) => EnumItem(Enum {
+            ItemKind::Enum(_, def, generics) => EnumItem(Enum {
                 variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
                 generics: clean_generics(generics, cx),
             }),
@@ -2854,11 +2854,11 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: clean_generics(generics, cx),
                 bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             }),
-            ItemKind::Union(_, ref variant_data, generics) => UnionItem(Union {
+            ItemKind::Union(_, variant_data, generics) => UnionItem(Union {
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
-            ItemKind::Struct(_, ref variant_data, generics) => StructItem(Struct {
+            ItemKind::Struct(_, variant_data, generics) => StructItem(Struct {
                 ctor_kind: variant_data.ctor_kind(),
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index e967fd40609..d684e6f8650 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -167,7 +167,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
 }
 
 fn usually_needs_space_between_keyword_and_open_delim(symbol: Symbol, span: Span) -> bool {
-    let ident = Ident { name: symbol, span };
+    let ident = Ident::new(symbol, span);
     let is_keyword = ident.is_used_keyword() || ident.is_unused_keyword();
     if !is_keyword {
         // An identifier that is not a keyword usually does not need a space
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bbe11bf56af..e45f28444fe 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,
                 })
@@ -777,16 +779,20 @@ impl Item {
                             // don't want it it `Item::attrs`.
                             None
                         }
-                        rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
-                            ..,
-                        )) => {
+                        rustc_hir::Attribute::Parsed(
+                            rustc_attr_data_structures::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
                         }
-                        _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
+                        _ => Some({
+                            let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
+                            assert_eq!(s.pop(), Some('\n'));
+                            s
+                        }),
                     }
                 } else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
                     Some(
@@ -1333,9 +1339,9 @@ pub(crate) enum WherePredicate {
 
 impl WherePredicate {
     pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
-        match *self {
-            WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
-            WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
+        match self {
+            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
+            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
             _ => None,
         }
     }
@@ -1705,13 +1711,13 @@ impl Type {
     ///
     /// [clean]: crate::clean
     pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
-        let t: PrimitiveType = match *self {
-            Type::Path { ref path } => return Some(path.def_id()),
-            DynTrait(ref bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
-            Primitive(p) => return cache.primitive_locations.get(&p).cloned(),
+        let t: PrimitiveType = match self {
+            Type::Path { path } => return Some(path.def_id()),
+            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
+            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
-            BorrowedRef { ref type_, .. } => return type_.def_id(cache),
-            Tuple(ref tys) => {
+            BorrowedRef { type_, .. } => return type_.def_id(cache),
+            Tuple(tys) => {
                 if tys.is_empty() {
                     PrimitiveType::Unit
                 } else {
@@ -1723,7 +1729,7 @@ impl Type {
             Array(..) => PrimitiveType::Array,
             Type::Pat(..) => PrimitiveType::Pat,
             RawPointer(..) => PrimitiveType::RawPointer,
-            QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
+            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
             Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
         };
         Primitive(t).def_id(cache)
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 4ef73ff48ed..f93aa8ffd0d 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -174,7 +174,7 @@ pub(crate) struct Options {
     pub(crate) expanded_args: Vec<String>,
 
     /// Arguments to be used when compiling doctests.
-    pub(crate) doctest_compilation_args: Vec<String>,
+    pub(crate) doctest_build_args: Vec<String>,
 }
 
 impl fmt::Debug for Options {
@@ -802,7 +802,7 @@ impl Options {
         let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
         let with_examples = matches.opt_strs("with-examples");
         let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
-        let doctest_compilation_args = matches.opt_strs("doctest-compilation-args");
+        let doctest_build_args = matches.opt_strs("doctest-build-arg");
 
         let unstable_features =
             rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
@@ -851,7 +851,7 @@ impl Options {
             scrape_examples_options,
             unstable_features,
             expanded_args: args,
-            doctest_compilation_args,
+            doctest_build_args,
         };
         let render_options = RenderOptions {
             output,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 829a9ca6e7d..ef70b862185 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -51,46 +51,6 @@ pub(crate) struct GlobalTestOptions {
     pub(crate) args_file: PathBuf,
 }
 
-/// Function used to split command line arguments just like a shell would.
-fn split_args(args: &str) -> Vec<String> {
-    let mut out = Vec::new();
-    let mut iter = args.chars();
-    let mut current = String::new();
-
-    while let Some(c) = iter.next() {
-        if c == '\\' {
-            if let Some(c) = iter.next() {
-                // If it's escaped, even a quote or a whitespace will be ignored.
-                current.push(c);
-            }
-        } else if c == '"' || c == '\'' {
-            while let Some(new_c) = iter.next() {
-                if new_c == c {
-                    break;
-                } else if new_c == '\\' {
-                    if let Some(c) = iter.next() {
-                        // If it's escaped, even a quote will be ignored.
-                        current.push(c);
-                    }
-                } else {
-                    current.push(new_c);
-                }
-            }
-        } else if " \n\t\r".contains(c) {
-            if !current.is_empty() {
-                out.push(current.clone());
-                current.clear();
-            }
-        } else {
-            current.push(c);
-        }
-    }
-    if !current.is_empty() {
-        out.push(current);
-    }
-    out
-}
-
 pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> {
     let mut file = File::create(file_path)
         .map_err(|error| format!("failed to create args file: {error:?}"))?;
@@ -119,9 +79,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) ->
         content.push(format!("-Z{unstable_option_str}"));
     }
 
-    for compilation_args in &options.doctest_compilation_args {
-        content.extend(split_args(compilation_args));
-    }
+    content.extend(options.doctest_build_args.clone());
 
     let content = content.join("\n");
 
@@ -262,11 +220,21 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
         Ok(None) => return,
         Err(error) => {
             eprintln!("{error}");
+            // Since some files in the temporary folder are still owned and alive, we need
+            // to manually remove the folder.
+            let _ = std::fs::remove_dir_all(temp_dir.path());
             std::process::exit(1);
         }
     };
 
-    run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests);
+    run_tests(
+        opts,
+        &rustdoc_options,
+        &unused_extern_reports,
+        standalone_tests,
+        mergeable_tests,
+        Some(temp_dir),
+    );
 
     let compiling_test_count = compiling_test_count.load(Ordering::SeqCst);
 
@@ -316,6 +284,8 @@ pub(crate) fn run_tests(
     unused_extern_reports: &Arc<Mutex<Vec<UnusedExterns>>>,
     mut standalone_tests: Vec<test::TestDescAndFn>,
     mergeable_tests: FxIndexMap<Edition, Vec<(DocTestBuilder, ScrapedDocTest)>>,
+    // We pass this argument so we can drop it manually before using `exit`.
+    mut temp_dir: Option<TempDir>,
 ) {
     let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1);
     test_args.insert(0, "rustdoctest".to_string());
@@ -382,9 +352,14 @@ pub(crate) fn run_tests(
     // `running 0 tests...`.
     if ran_edition_tests == 0 || !standalone_tests.is_empty() {
         standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice()));
-        test::test_main(&test_args, standalone_tests, None);
+        test::test_main_with_exit_callback(&test_args, standalone_tests, None, || {
+            // We ensure temp dir destructor is called.
+            std::mem::drop(temp_dir.take());
+        });
     }
     if nb_errors != 0 {
+        // We ensure temp dir destructor is called.
+        std::mem::drop(temp_dir);
         // libtest::ERROR_EXIT_CODE is not public but it's the same value.
         std::process::exit(101);
     }
@@ -450,7 +425,7 @@ enum TestFailure {
 }
 
 enum DirState {
-    Temp(tempfile::TempDir),
+    Temp(TempDir),
     Perm(PathBuf),
 }
 
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index 4194abc8d57..d4fbfb12582 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -301,8 +301,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
 
     let filename = FileName::anon_source_code(&wrapped_source);
 
-    // Any errors in parsing should also appear when the doctest is compiled for real, so just
-    // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
     let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
     let fallback_bundle = rustc_errors::fallback_fluent_bundle(
         rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
@@ -311,7 +309,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
     info.supports_color =
         HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone())
             .supports_color();
-
+    // Any errors in parsing should also appear when the doctest is compiled for real, so just
+    // send all the errors that the parser emits directly into a `Sink` instead of stderr.
     let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
 
     // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
@@ -339,9 +338,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
         *prev_span_hi = hi;
     }
 
-    // Recurse through functions body. It is necessary because the doctest source code is
-    // wrapped in a function to limit the number of AST errors. If we don't recurse into
-    // functions, we would thing all top-level items (so basically nothing).
     fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool {
         let mut is_extern_crate = false;
         if !info.has_global_allocator
@@ -351,8 +347,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
         }
         match item.kind {
             ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => {
-                // We only push if it's the top item because otherwise, we would duplicate
-                // its content since the top-level item was already added.
                 if fn_item.ident.name == sym::main {
                     info.has_main_fn = true;
                 }
@@ -412,44 +406,41 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
                 let mut is_extern_crate = false;
                 match stmt.kind {
                     StmtKind::Item(ref item) => {
-                        is_extern_crate = check_item(&item, &mut info, crate_name);
-                    }
-                    StmtKind::Expr(ref expr) => {
-                        if matches!(expr.kind, ast::ExprKind::Err(_)) {
-                            reset_error_count(&psess);
-                            return Err(());
-                        }
-                        has_non_items = true;
+                        is_extern_crate = check_item(item, &mut info, crate_name);
                     }
                     // We assume that the macro calls will expand to item(s) even though they could
-                    // expand to statements and expressions. And the simple fact that we're trying
-                    // to retrieve a `main` function inside it is a terrible idea.
+                    // expand to statements and expressions.
                     StmtKind::MacCall(ref mac_call) => {
-                        if info.has_main_fn {
-                            continue;
-                        }
-                        let mut iter = mac_call.mac.args.tokens.iter();
-
-                        while let Some(token) = iter.next() {
-                            if let TokenTree::Token(token, _) = token
-                                && let TokenKind::Ident(name, _) = token.kind
-                                && name == kw::Fn
-                                && let Some(TokenTree::Token(fn_token, _)) = iter.peek()
-                                && let TokenKind::Ident(fn_name, _) = fn_token.kind
-                                && fn_name == sym::main
-                                && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = {
-                                    iter.next();
-                                    iter.peek()
+                        if !info.has_main_fn {
+                            // For backward compatibility, we look for the token sequence `fn main(…)`
+                            // in the macro input (!) to crudely detect main functions "masked by a
+                            // wrapper macro". For the record, this is a horrible heuristic!
+                            // See <https://github.com/rust-lang/rust/issues/56898>.
+                            let mut iter = mac_call.mac.args.tokens.iter();
+                            while let Some(token) = iter.next() {
+                                if let TokenTree::Token(token, _) = token
+                                    && let TokenKind::Ident(kw::Fn, _) = token.kind
+                                    && let Some(TokenTree::Token(ident, _)) = iter.peek()
+                                    && let TokenKind::Ident(sym::main, _) = ident.kind
+                                    && let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, _)) = {
+                                        iter.next();
+                                        iter.peek()
+                                    }
+                                {
+                                    info.has_main_fn = true;
+                                    break;
                                 }
-                            {
-                                info.has_main_fn = true;
-                                break;
                             }
                         }
                     }
-                    _ => {
+                    StmtKind::Expr(ref expr) => {
+                        if matches!(expr.kind, ast::ExprKind::Err(_)) {
+                            reset_error_count(&psess);
+                            return Err(());
+                        }
                         has_non_items = true;
                     }
+                    StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty => has_non_items = true,
                 }
 
                 // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to
diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs
index 497a8d7c4a7..b3a3ce08a05 100644
--- a/src/librustdoc/doctest/markdown.rs
+++ b/src/librustdoc/doctest/markdown.rs
@@ -116,6 +116,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> {
         &Arc::new(Mutex::new(Vec::new())),
         standalone_tests,
         mergeable_tests,
+        None,
     );
     Ok(())
 }
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index 49add73e9d6..618c2041b43 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -382,28 +382,6 @@ fn main() {
 }
 
 #[test]
-fn check_split_args() {
-    fn compare(input: &str, expected: &[&str]) {
-        let output = super::split_args(input);
-        let expected = expected.iter().map(|s| s.to_string()).collect::<Vec<_>>();
-        assert_eq!(expected, output, "test failed for {input:?}");
-    }
-
-    compare("'a' \"b\"c", &["a", "bc"]);
-    compare("'a' \"b \"c d", &["a", "b c", "d"]);
-    compare("'a' \"b\\\"c\"", &["a", "b\"c"]);
-    compare("'a\"'", &["a\""]);
-    compare("\"a'\"", &["a'"]);
-    compare("\\ a", &[" a"]);
-    compare("\\\\", &["\\"]);
-    compare("a'", &["a"]);
-    compare("a          ", &["a"]);
-    compare("a          b", &["a", "b"]);
-    compare("a\n\t \rb", &["a", "b"]);
-    compare("a\n\t1 \rb", &["a", "1", "b"]);
-}
-
-#[test]
 fn comment_in_attrs() {
     // If there is an inline code comment after attributes, we need to ensure that
     // a backline will be added to prevent generating code "inside" it (and thus generating)
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/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index de6537e992f..3aba7a370ad 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -70,12 +70,12 @@ impl Serialize for ItemType {
 
 impl<'a> From<&'a clean::Item> for ItemType {
     fn from(item: &'a clean::Item) -> ItemType {
-        let kind = match item.kind {
-            clean::StrippedItem(box ref item) => item,
-            ref kind => kind,
+        let kind = match &item.kind {
+            clean::StrippedItem(box item) => item,
+            kind => kind,
         };
 
-        match *kind {
+        match kind {
             clean::ModuleItem(..) => ItemType::Module,
             clean::ExternCrateItem { .. } => ItemType::ExternCrate,
             clean::ImportItem(..) => ItemType::Import,
@@ -103,7 +103,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
             clean::ForeignTypeItem => ItemType::ForeignType,
             clean::KeywordItem => ItemType::Keyword,
             clean::TraitAliasItem(..) => ItemType::TraitAlias,
-            clean::ProcMacroItem(ref mac) => match mac.kind {
+            clean::ProcMacroItem(mac) => match mac.kind {
                 MacroKind::Bang => ItemType::Macro,
                 MacroKind::Attr => ItemType::ProcAttribute,
                 MacroKind::Derive => ItemType::ProcDerive,
@@ -134,22 +134,15 @@ impl ItemType {
             DefKind::Trait => Self::Trait,
             DefKind::TyAlias => Self::TypeAlias,
             DefKind::TraitAlias => Self::TraitAlias,
-            DefKind::Macro(kind) => match kind {
-                MacroKind::Bang => ItemType::Macro,
-                MacroKind::Attr => ItemType::ProcAttribute,
-                MacroKind::Derive => ItemType::ProcDerive,
-            },
+            DefKind::Macro(MacroKind::Bang) => ItemType::Macro,
+            DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute,
+            DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive,
             DefKind::ForeignTy => Self::ForeignType,
             DefKind::Variant => Self::Variant,
             DefKind::Field => Self::StructField,
             DefKind::AssocTy => Self::AssocType,
-            DefKind::AssocFn => {
-                if let Some(DefKind::Trait) = parent_kind {
-                    Self::TyMethod
-                } else {
-                    Self::Method
-                }
-            }
+            DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => Self::TyMethod,
+            DefKind::AssocFn => Self::Method,
             DefKind::Ctor(CtorOf::Struct, _) => Self::Struct,
             DefKind::Ctor(CtorOf::Variant, _) => Self::Variant,
             DefKind::AssocConst => Self::AssocConst,
@@ -170,7 +163,7 @@ impl ItemType {
     }
 
     pub(crate) fn as_str(&self) -> &'static str {
-        match *self {
+        match self {
             ItemType::Module => "mod",
             ItemType::ExternCrate => "externcrate",
             ItemType::Import => "import",
@@ -199,10 +192,10 @@ impl ItemType {
         }
     }
     pub(crate) fn is_method(&self) -> bool {
-        matches!(*self, ItemType::Method | ItemType::TyMethod)
+        matches!(self, ItemType::Method | ItemType::TyMethod)
     }
     pub(crate) fn is_adt(&self) -> bool {
-        matches!(*self, ItemType::Struct | ItemType::Union | ItemType::Enum)
+        matches!(self, ItemType::Struct | ItemType::Union | ItemType::Enum)
     }
 }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 299fd6b9adb..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;
@@ -856,15 +856,15 @@ fn fmt_type(
 ) -> fmt::Result {
     trace!("fmt_type(t = {t:?})");
 
-    match *t {
+    match t {
         clean::Generic(name) => f.write_str(name.as_str()),
         clean::SelfTy => f.write_str("Self"),
-        clean::Type::Path { ref path } => {
+        clean::Type::Path { path } => {
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
             let did = path.def_id();
             resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
         }
-        clean::DynTrait(ref bounds, ref lt) => {
+        clean::DynTrait(bounds, lt) => {
             f.write_str("dyn ")?;
             tybounds(bounds, lt, cx).fmt(f)
         }
@@ -872,8 +872,8 @@ fn fmt_type(
         clean::Primitive(clean::PrimitiveType::Never) => {
             primitive_link(f, PrimitiveType::Never, format_args!("!"), cx)
         }
-        clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx),
-        clean::BareFunction(ref decl) => {
+        &clean::Primitive(prim) => primitive_link(f, prim, format_args!("{}", prim.as_sym()), cx),
+        clean::BareFunction(decl) => {
             print_higher_ranked_params_with_space(&decl.generic_params, cx, "for").fmt(f)?;
             decl.safety.print_with_space().fmt(f)?;
             print_abi_with_space(decl.abi).fmt(f)?;
@@ -884,11 +884,11 @@ fn fmt_type(
             }
             decl.decl.print(cx).fmt(f)
         }
-        clean::UnsafeBinder(ref binder) => {
+        clean::UnsafeBinder(binder) => {
             print_higher_ranked_params_with_space(&binder.generic_params, cx, "unsafe").fmt(f)?;
             binder.ty.print(cx).fmt(f)
         }
-        clean::Tuple(ref typs) => match &typs[..] {
+        clean::Tuple(typs) => match &typs[..] {
             &[] => primitive_link(f, PrimitiveType::Unit, format_args!("()"), cx),
             [one] => {
                 if let clean::Generic(name) = one {
@@ -925,45 +925,36 @@ fn fmt_type(
                 }
             }
         },
-        clean::Slice(ref t) => match **t {
-            clean::Generic(name) => {
-                primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
-            }
-            _ => {
-                write!(f, "[")?;
-                t.print(cx).fmt(f)?;
-                write!(f, "]")
-            }
-        },
-        clean::Type::Pat(ref t, ref pat) => {
+        clean::Slice(box clean::Generic(name)) => {
+            primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
+        }
+        clean::Slice(t) => {
+            write!(f, "[")?;
+            t.print(cx).fmt(f)?;
+            write!(f, "]")
+        }
+        clean::Type::Pat(t, pat) => {
             fmt::Display::fmt(&t.print(cx), f)?;
             write!(f, " is {pat}")
         }
-        clean::Array(ref t, ref n) => match **t {
-            clean::Generic(name) if !f.alternate() => primitive_link(
-                f,
-                PrimitiveType::Array,
-                format_args!("[{name}; {n}]", n = Escape(n)),
-                cx,
-            ),
-            _ => {
-                write!(f, "[")?;
-                t.print(cx).fmt(f)?;
-                if f.alternate() {
-                    write!(f, "; {n}")?;
-                } else {
-                    write!(f, "; ")?;
-                    primitive_link(
-                        f,
-                        PrimitiveType::Array,
-                        format_args!("{n}", n = Escape(n)),
-                        cx,
-                    )?;
-                }
-                write!(f, "]")
+        clean::Array(box clean::Generic(name), n) if !f.alternate() => primitive_link(
+            f,
+            PrimitiveType::Array,
+            format_args!("[{name}; {n}]", n = Escape(n)),
+            cx,
+        ),
+        clean::Array(t, n) => {
+            write!(f, "[")?;
+            t.print(cx).fmt(f)?;
+            if f.alternate() {
+                write!(f, "; {n}")?;
+            } else {
+                write!(f, "; ")?;
+                primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?;
             }
-        },
-        clean::RawPointer(m, ref t) => {
+            write!(f, "]")
+        }
+        clean::RawPointer(m, t) => {
             let m = match m {
                 hir::Mutability::Mut => "mut",
                 hir::Mutability::Not => "const",
@@ -991,7 +982,7 @@ fn fmt_type(
                 t.print(cx).fmt(f)
             }
         }
-        clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
+        clean::BorrowedRef { lifetime: l, mutability, type_: ty } => {
             let lt = fmt::from_fn(|f| match l {
                 Some(l) => write!(f, "{} ", l.print()),
                 _ => Ok(()),
@@ -1028,11 +1019,11 @@ fn fmt_type(
             }
             Ok(())
         }
-        clean::ImplTrait(ref bounds) => {
+        clean::ImplTrait(bounds) => {
             f.write_str("impl ")?;
             print_generic_bounds(bounds, cx).fmt(f)
         }
-        clean::QPath(box clean::QPathData {
+        &clean::QPath(box clean::QPathData {
             ref assoc,
             ref self_type,
             ref trait_,
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index c943d3ad4d0..2db1ea8450c 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -9,7 +9,7 @@ use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_lexer::{Cursor, LiteralKind, TokenKind};
+use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, DUMMY_SP, Span};
@@ -638,7 +638,8 @@ impl<'src> Classifier<'src> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondence_map`.
     fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self {
-        let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) });
+        let tokens =
+            PeekIter::new(TokenIter { src, cursor: Cursor::new(src, FrontmatterAllowed::Yes) });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
             tokens,
@@ -884,6 +885,7 @@ impl<'src> Classifier<'src> {
             | TokenKind::At
             | TokenKind::Tilde
             | TokenKind::Colon
+            | TokenKind::Frontmatter { .. }
             | TokenKind::Unknown => return no_highlight(sink),
 
             TokenKind::Question => Class::QuestionMark,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index beaa6497b8c..3492df99955 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};
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 477a79d63e9..a3c6bf98161 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -43,6 +43,7 @@ nav.sub {
 	--settings-button-border-focus: #717171;
 	--sidebar-background-color: #f5f5f5;
 	--sidebar-background-color-hover: #e0e0e0;
+	--sidebar-border-color: #ddd;
 	--code-block-background-color: #f5f5f5;
 	--scrollbar-track-background-color: #dcdcdc;
 	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
@@ -149,6 +150,7 @@ nav.sub {
 		--settings-button-border-focus: #ffb900;
 		--sidebar-background-color: #505050;
 		--sidebar-background-color-hover: #676767;
+		--sidebar-border-color: #2A2A2A;
 		--code-block-background-color: #2A2A2A;
 		--scrollbar-track-background-color: #717171;
 		--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 19ac24a5d6e..a81d5c9c49b 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1,4 +1,6 @@
-/* When static files are updated, their suffixes need to be updated.
+/* ignore-tidy-filelength */
+/*
+	When static files are updated, their suffixes need to be updated.
 	1. In the top directory run:
 		./x.py doc --stage 1 library/core
 	2. Find the directory containing files named with updated suffixes:
@@ -55,6 +57,9 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 	--collapse-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
 	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
 	d="M3,8l4,4l4,-4m-4,4M3,4l4,4l4,-4" stroke="black" stroke-width="2"/></svg>');
+	--hamburger-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
+		viewBox="0 0 22 22" fill="none" stroke="black">\
+		<path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>');
 }
 
 :root.sans-serif {
@@ -493,12 +498,13 @@ img {
 	top: 0;
 	left: 0;
 	z-index: var(--desktop-sidebar-z-index);
+	/* resize indicator: hide this when on touch or mobile */
+	border-right: solid 1px var(--sidebar-border-color);
 }
 
 .rustdoc.src .sidebar {
 	flex-basis: 50px;
 	width: 50px;
-	border-right: 1px solid;
 	overflow-x: hidden;
 	/* The sidebar is by default hidden  */
 	overflow-y: hidden;
@@ -512,12 +518,27 @@ img {
 .sidebar-resizer {
 	touch-action: none;
 	width: 9px;
-	cursor: col-resize;
+	cursor: ew-resize;
 	z-index: calc(var(--desktop-sidebar-z-index) + 1);
 	position: fixed;
 	height: 100%;
-	/* make sure there's a 1px gap between the scrollbar and resize handle */
-	left: calc(var(--desktop-sidebar-width) + 1px);
+	left: var(--desktop-sidebar-width);
+	display: flex;
+	align-items: center;
+	justify-content: flex-start;
+	color: var(--right-side-color);
+}
+.sidebar-resizer::before {
+	content: "";
+	border-right: dotted 2px currentColor;
+	width: 2px;
+	height: 12px;
+}
+.sidebar-resizer::after {
+	content: "";
+	border-right: dotted 2px currentColor;
+	width: 2px;
+	height: 16px;
 }
 
 .rustdoc.src .sidebar-resizer {
@@ -540,11 +561,12 @@ img {
 }
 
 .sidebar-resizing * {
-	cursor: col-resize !important;
+	cursor: ew-resize !important;
 }
 
 .sidebar-resizing .sidebar {
 	position: fixed;
+	border-right: solid 2px var(--sidebar-resizer-active);
 }
 .sidebar-resizing > body {
 	padding-left: var(--resizing-sidebar-width);
@@ -558,8 +580,9 @@ img {
 	margin: 0;
 	/* when active or hovered, place resizer glow on top of the sidebar (right next to, or even
 	   on top of, the scrollbar) */
-	left: var(--desktop-sidebar-width);
+	left: calc(var(--desktop-sidebar-width) - 1px);
 	border-left: solid 1px var(--sidebar-resizer-hover);
+	color: var(--sidebar-resizer-hover);
 }
 
 .src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,
@@ -575,21 +598,20 @@ img {
 		/* too easy to hit the resizer while trying to hit the [-] toggle */
 		display: none !important;
 	}
+	.sidebar {
+		/* resize indicator: hide this when on touch or mobile */
+		border-right: none;
+	}
 }
 
 .sidebar-resizer.active {
 	/* make the resize tool bigger when actually resizing, to avoid :hover styles on other stuff
 		while resizing */
 	padding: 0 140px;
-	width: 2px;
+	width: calc(140px + 140px + 9px + 2px);
 	margin-left: -140px;
 	border-left: none;
-}
-.sidebar-resizer.active::before {
-	border-left: solid 2px var(--sidebar-resizer-active);
-	display: block;
-	height: 100%;
-	content: "";
+	color: var(--sidebar-resizer-active);
 }
 
 .sidebar, .mobile-topbar, .sidebar-menu-toggle,
@@ -2001,9 +2023,11 @@ a.tooltip:hover::after {
 	display: flex;
 	margin-right: 4px;
 	position: fixed;
-	left: 6px;
 	height: 34px;
 	width: 34px;
+}
+.hide-sidebar #sidebar-button {
+	left: 6px;
 	background-color: var(--main-background-color);
 	z-index: 1;
 }
@@ -2019,6 +2043,8 @@ a.tooltip:hover::after {
 	align-items: center;
 	justify-content: center;
 	flex-direction: column;
+}
+#settings-menu > a, #help-button > a, button#toggle-all-docs {
 	border: 1px solid transparent;
 	border-radius: var(--button-border-radius);
 	color: var(--main-color);
@@ -2031,14 +2057,15 @@ a.tooltip:hover::after {
 	min-width: 0;
 }
 #sidebar-button > a {
-	background-color: var(--button-background-color);
-	border-color: var(--border-color);
+	background-color: var(--sidebar-background-color);
 	width: 33px;
 }
+#sidebar-button > a:hover, #sidebar-button > a:focus-visible {
+	background-color: var(--main-background-color);
+}
 
 #settings-menu > a:hover, #settings-menu > a:focus-visible,
 #help-button > a:hover, #help-button > a:focus-visible,
-#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
 button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
 	border-color: var(--settings-button-border-focus);
 	text-decoration: none;
@@ -2405,10 +2432,9 @@ However, it's not needed with smaller screen width because the doc/code block is
 	use hamburger button */
 .src #sidebar-button > a::before, .sidebar-menu-toggle::before {
 	/* hamburger button image */
-	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
-		viewBox="0 0 22 22" fill="none" stroke="black">\
-		<path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>');
+	content: var(--hamburger-image);
 	opacity: 0.75;
+	filter: var(--mobile-sidebar-menu-filter);
 }
 .sidebar-menu-toggle:hover::before,
 .sidebar-menu-toggle:active::before,
@@ -2416,17 +2442,6 @@ However, it's not needed with smaller screen width because the doc/code block is
 	opacity: 1;
 }
 
-/* src sidebar button opens a folder view */
-.src #sidebar-button > a::before {
-	/* folder image */
-	content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
-		viewBox="0 0 22 22" fill="none" stroke="black">\
-		<path d="M16,9v-4h-6v-1l-2,-2h-4l-2,2v16h13L21,9h-15L2,19" stroke-width="1.25"/>\
-		<path d="M15,7h-11v3" stroke-width="0.75"/>\
-		<path d="M3.75,10v1.25" stroke-width="0.375"/></svg>');
-	opacity: 0.75;
-}
-
 /* Media Queries */
 
 /* Make sure all the buttons line wrap at the same time */
@@ -2513,6 +2528,8 @@ in src-script.js and main.js
 		/* Reduce height slightly to account for mobile topbar. */
 		height: calc(100vh - 45px);
 		width: 200px;
+		/* resize indicator: hide this when on touch or mobile */
+		border-right: none;
 	}
 
 	/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
@@ -2611,9 +2628,6 @@ in src-script.js and main.js
 		width: 22px;
 		height: 22px;
 	}
-	.sidebar-menu-toggle::before {
-		filter: var(--mobile-sidebar-menu-filter);
-	}
 	.sidebar-menu-toggle:hover {
 		background: var(--main-background-color);
 	}
@@ -2671,6 +2685,14 @@ in src-script.js and main.js
 		margin: 0 0 -25px 0;
 		padding: var(--nav-sub-mobile-padding);
 	}
+
+	html:not(.src-sidebar-expanded) .src #sidebar-button > a {
+		background-color: var(--main-background-color);
+	}
+	html:not(.src-sidebar-expanded) .src #sidebar-button > a:hover,
+	html:not(.src-sidebar-expanded) .src #sidebar-button > a:focus-visible {
+		background-color: var(--sidebar-background-color);
+	}
 }
 
 
@@ -2896,6 +2918,7 @@ by default.
 	--settings-button-border-focus: #717171;
 	--sidebar-background-color: #f5f5f5;
 	--sidebar-background-color-hover: #e0e0e0;
+	--sidebar-border-color: #ddd;
 	--code-block-background-color: #f5f5f5;
 	--scrollbar-track-background-color: #dcdcdc;
 	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
@@ -3001,6 +3024,7 @@ by default.
 	--settings-button-border-focus: #ffb900;
 	--sidebar-background-color: #505050;
 	--sidebar-background-color-hover: #676767;
+	--sidebar-border-color: #999;
 	--code-block-background-color: #2A2A2A;
 	--scrollbar-track-background-color: #717171;
 	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
@@ -3113,6 +3137,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--settings-button-border-focus: #e0e0e0;
 	--sidebar-background-color: #14191f;
 	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+	--sidebar-border-color: #5c6773;
 	--code-block-background-color: #191f26;
 	--scrollbar-track-background-color: transparent;
 	--scrollbar-thumb-background-color: #5c6773;
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 5ef376f4acb..7af99e7097c 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -114,7 +114,7 @@
         {% endif %}
         {{ sidebar|safe }}
     </nav> {# #}
-    <div class="sidebar-resizer"></div> {# #}
+    <div class="sidebar-resizer" title="Drag to resize sidebar"></div> {# #}
     <main>
         {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
             {# defined in storage.js to avoid duplicating complex UI across every page #}
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 44bd96a7e45..001668c54a7 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -11,7 +11,6 @@
 #![feature(if_let_guard)]
 #![feature(impl_trait_in_assoc_type)]
 #![feature(iter_intersperse)]
-#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(round_char_boundary)]
 #![feature(test)]
@@ -37,6 +36,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;
@@ -73,9 +73,11 @@ extern crate tikv_jemalloc_sys as jemalloc_sys;
 
 use std::env::{self, VarError};
 use std::io::{self, IsTerminal};
+use std::path::Path;
 use std::process;
 
 use rustc_errors::DiagCtxtHandle;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option};
@@ -170,12 +172,28 @@ pub fn main() {
     // NOTE: this compiles both versions of tracing unconditionally, because
     // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
     // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
-    // NOTE: The reason this doesn't show double logging when `download-rustc = false` and
-    // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
-    // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
 
-    init_logging(&early_dcx);
-    rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
+    crate::init_logging(&early_dcx);
+    match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
+        Ok(()) => {}
+        // With `download-rustc = true` there are definitely 2 distinct tracing crates in the
+        // dependency graph: one in the downloaded sysroot and one built just now as a dependency of
+        // rustdoc. So the sysroot's tracing is definitely not yet initialized here.
+        //
+        // But otherwise, depending on link style, there may or may not be 2 tracing crates in play.
+        // The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency
+        // on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's
+        // tracing dependency is distinct from this one and also needs to be initialized (using the
+        // same RUSTDOC_LOG environment variable for both). Other build systems may use just a
+        // single tracing crate throughout the rustc and rustdoc build.
+        //
+        // The reason initializing 2 tracings does not show double logging when `download-rustc =
+        // false` and `debug_logging = true` is because all rustc logging goes only to its version
+        // of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version
+        // (the one in Cargo.toml).
+        Err(rustc_log::Error::AlreadyInit(_)) => {}
+        Err(error) => early_dcx.early_fatal(error.to_string()),
+    }
 
     let exit_code = rustc_driver::catch_with_exit_code(|| {
         let at_args = rustc_driver::args::raw_args(&early_dcx);
@@ -638,9 +656,9 @@ fn opts() -> Vec<RustcOptGroup> {
             Unstable,
             Multi,
             "",
-            "doctest-compilation-args",
-            "",
-            "add arguments to be used when compiling doctests",
+            "doctest-build-arg",
+            "One argument (of possibly many) to be used when compiling doctests",
+            "ARG",
         ),
         opt(
             Unstable,
@@ -888,6 +906,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
                 rustc_interface::passes::write_dep_info(tcx);
             }
 
+            if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
+                dump_feature_usage_metrics(tcx, metrics_dir);
+            }
+
             if run_check {
                 // Since we're in "check" mode, no need to generate anything beyond this point.
                 return;
@@ -907,3 +929,16 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
         })
     })
 }
+
+fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
+    let hash = tcxt.crate_hash(LOCAL_CRATE);
+    let crate_name = tcxt.crate_name(LOCAL_CRATE);
+    let metrics_file_name = format!("unstable_feature_usage_metrics-{crate_name}-{hash}.json");
+    let metrics_path = metrics_dir.join(metrics_file_name);
+    if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
+        // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit
+        // default metrics" to only produce a warning when metrics are enabled by default and emit
+        // an error only when the user manually enables metrics
+        tcxt.dcx().err(format!("cannot emit feature usage metrics: {error}"));
+    }
+}
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index dcc27cd62e3..b09ea056885 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -196,14 +196,6 @@ declare_rustdoc_lint! {
     "detects redundant explicit links in doc comments"
 }
 
-declare_rustdoc_lint! {
-    /// This compatibility lint checks for Markdown syntax that works in the old engine but not
-    /// the new one.
-    UNPORTABLE_MARKDOWN,
-    Warn,
-    "detects markdown that is interpreted differently in different parser"
-}
-
 pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
     vec![
         BROKEN_INTRA_DOC_LINKS,
@@ -217,7 +209,6 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         MISSING_CRATE_LEVEL_DOCS,
         UNESCAPED_BACKTICKS,
         REDUNDANT_EXPLICIT_LINKS,
-        UNPORTABLE_MARKDOWN,
     ]
 });
 
@@ -241,4 +232,5 @@ pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) {
         .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links");
     lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls");
     lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls");
+    lint_store.register_removed("rustdoc::unportable_markdown", "old parser removed");
 }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 36f5889dcf4..f3e2138d1a5 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -496,12 +496,21 @@ impl<'tcx> LinkCollector<'_, 'tcx> {
 
         // Try looking for methods and associated items.
         // NB: `path_root` could be empty when resolving in the root namespace (e.g. `::std`).
-        let (path_root, item_str) = path_str.rsplit_once("::").ok_or_else(|| {
-            // If there's no `::`, it's not an associated item.
-            // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
-            debug!("found no `::`, assuming {path_str} was correctly not in scope");
-            UnresolvedPath { item_id, module_id, partial_res: None, unresolved: path_str.into() }
-        })?;
+        let (path_root, item_str) = match path_str.rsplit_once("::") {
+            Some(res @ (_path_root, item_str)) if !item_str.is_empty() => res,
+            _ => {
+                // If there's no `::`, or the `::` is at the end (e.g. `String::`) it's not an
+                // associated item. So we can be sure that `rustc_resolve` was accurate when it
+                // said it wasn't resolved.
+                debug!("`::` missing or at end, assuming {path_str} was not in scope");
+                return Err(UnresolvedPath {
+                    item_id,
+                    module_id,
+                    partial_res: None,
+                    unresolved: path_str.into(),
+                });
+            }
+        };
         let item_name = Symbol::intern(item_str);
 
         // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
index 1ecb53e61ac..7740d14148b 100644
--- a/src/librustdoc/passes/lint.rs
+++ b/src/librustdoc/passes/lint.rs
@@ -6,7 +6,6 @@ mod check_code_block_syntax;
 mod html_tags;
 mod redundant_explicit_links;
 mod unescaped_backticks;
-mod unportable_markdown;
 
 use super::Pass;
 use crate::clean::*;
@@ -49,9 +48,6 @@ impl DocVisitor<'_> for Linter<'_, '_> {
             }
             if may_have_block_comment_or_html {
                 html_tags::visit_item(self.cx, item, hir_id, &dox);
-                unportable_markdown::visit_item(self.cx, item, hir_id, &dox);
-            } else if may_have_link {
-                unportable_markdown::visit_item(self.cx, item, hir_id, &dox);
             }
         }
 
diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs
deleted file mode 100644
index 95646413a2d..00000000000
--- a/src/librustdoc/passes/lint/unportable_markdown.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-//! Detects specific markdown syntax that's different between pulldown-cmark
-//! 0.9 and 0.11.
-//!
-//! This is a mitigation for old parser bugs that affected some
-//! real crates' docs. The old parser claimed to comply with CommonMark,
-//! but it did not. These warnings will eventually be removed,
-//! though some of them may become Clippy lints.
-//!
-//! <https://github.com/rust-lang/rust/pull/121659#issuecomment-1992752820>
-//!
-//! <https://rustc-dev-guide.rust-lang.org/bug-fix-procedure.html#add-the-lint-to-the-list-of-removed-lists>
-
-use std::collections::{BTreeMap, BTreeSet};
-
-use rustc_hir::HirId;
-use rustc_lint_defs::Applicability;
-use rustc_resolve::rustdoc::source_span_for_markdown_range;
-use {pulldown_cmark as cmarkn, pulldown_cmark_old as cmarko};
-
-use crate::clean::Item;
-use crate::core::DocContext;
-
-pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
-    let tcx = cx.tcx;
-
-    // P1: unintended strikethrough was fixed by requiring single-tildes to flank
-    // the same way underscores do, so nothing is done here
-
-    // P2: block quotes without following space parsed wrong
-    //
-    // This is the set of starting points for block quotes with no space after
-    // the `>`. It is populated by the new parser, and if the old parser fails to
-    // clear it out, it'll produce a warning.
-    let mut spaceless_block_quotes = BTreeSet::new();
-
-    // P3: missing footnote references
-    //
-    // This is populated by listening for FootnoteReference from
-    // the new parser and old parser.
-    let mut missing_footnote_references = BTreeMap::new();
-    let mut found_footnote_references = BTreeSet::new();
-
-    // populate problem cases from new parser
-    {
-        pub fn main_body_opts_new() -> cmarkn::Options {
-            cmarkn::Options::ENABLE_TABLES
-                | cmarkn::Options::ENABLE_FOOTNOTES
-                | cmarkn::Options::ENABLE_STRIKETHROUGH
-                | cmarkn::Options::ENABLE_TASKLISTS
-                | cmarkn::Options::ENABLE_SMART_PUNCTUATION
-        }
-        let parser_new = cmarkn::Parser::new_ext(dox, main_body_opts_new()).into_offset_iter();
-        for (event, span) in parser_new {
-            if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event {
-                if !dox[span.clone()].starts_with("> ") {
-                    spaceless_block_quotes.insert(span.start);
-                }
-            }
-            if let cmarkn::Event::FootnoteReference(_) = event {
-                found_footnote_references.insert(span.start + 1);
-            }
-        }
-    }
-
-    // remove cases where they don't actually differ
-    {
-        pub fn main_body_opts_old() -> cmarko::Options {
-            cmarko::Options::ENABLE_TABLES
-                | cmarko::Options::ENABLE_FOOTNOTES
-                | cmarko::Options::ENABLE_STRIKETHROUGH
-                | cmarko::Options::ENABLE_TASKLISTS
-                | cmarko::Options::ENABLE_SMART_PUNCTUATION
-        }
-        let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter();
-        for (event, span) in parser_old {
-            if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event
-                && !dox[span.clone()].starts_with("> ")
-            {
-                spaceless_block_quotes.remove(&span.start);
-            }
-            if let cmarko::Event::FootnoteReference(_) = event
-                && !found_footnote_references.contains(&(span.start + 1))
-            {
-                missing_footnote_references.insert(span.start + 1, span);
-            }
-        }
-    }
-
-    for start in spaceless_block_quotes {
-        let (span, precise) =
-            source_span_for_markdown_range(tcx, dox, &(start..start + 1), &item.attrs.doc_strings)
-                .map(|span| (span, true))
-                .unwrap_or_else(|| (item.attr_span(tcx), false));
-
-        tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| {
-            lint.primary_message("unportable markdown");
-            lint.help("confusing block quote with no space after the `>` marker".to_string());
-            if precise {
-                lint.span_suggestion(
-                    span.shrink_to_hi(),
-                    "if the quote is intended, add a space",
-                    " ",
-                    Applicability::MaybeIncorrect,
-                );
-                lint.span_suggestion(
-                    span.shrink_to_lo(),
-                    "if it should not be a quote, escape it",
-                    "\\",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        });
-    }
-    for (_caret, span) in missing_footnote_references {
-        let (ref_span, precise) =
-            source_span_for_markdown_range(tcx, dox, &span, &item.attrs.doc_strings)
-                .map(|span| (span, true))
-                .unwrap_or_else(|| (item.attr_span(tcx), false));
-
-        tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| {
-            lint.primary_message("unportable markdown");
-            if precise {
-                lint.span_suggestion(
-                    ref_span.shrink_to_lo(),
-                    "if it should not be a footnote, escape it",
-                    "\\",
-                    Applicability::MaybeIncorrect,
-                );
-            }
-            if dox.as_bytes().get(span.end) == Some(&b'[') {
-                lint.help("confusing footnote reference and link");
-                if precise {
-                    lint.span_suggestion(
-                        ref_span.shrink_to_hi(),
-                        "if the footnote is intended, add a space",
-                        " ",
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    lint.help("there should be a space between the link and the footnote");
-                }
-            }
-        });
-    }
-}
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/llvm-project b/src/llvm-project
-Subproject a9865ceca08101071e25f3bba97bba8bf0ea971
+Subproject c1118fdbb3024157df7f4cfe765f2b0b4339e8a
diff --git a/src/stage0 b/src/stage0
index 06080e3a8c1..8ca6860490c 100644
--- a/src/stage0
+++ b/src/stage0
@@ -13,466 +13,466 @@ nightly_branch=master
 # All changes below this comment will be overridden the next time the
 # tool is executed.
 
-compiler_date=2025-04-02
+compiler_date=2025-05-12
 compiler_version=beta
-rustfmt_date=2025-04-02
+rustfmt_date=2025-05-12
 rustfmt_version=nightly
 
-dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.gz=42fbc48c6f9034c1d47029491e0adc7aaa1adecf429e22ea9eb6d36225ed13e7
-dist/2025-04-02/rustc-beta-aarch64-apple-darwin.tar.xz=08f88363fd42d66d537c0a296502f94c3a3fecf59a004613c9acff33eb0b0207
-dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.gz=ea47adaa63abd18bf0c11cdb381eefb2874994527005cbccc0dcace33191f9c6
-dist/2025-04-02/rustc-beta-aarch64-pc-windows-msvc.tar.xz=cefea68c789907a45f0bd4233da2e3406287ac55d1c33f8612ec1aa006b853f0
-dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=38fa4ce395641a988247ee58c334389eda62fc1d3c0fb45157f24578319925d8
-dist/2025-04-02/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=d8d0b459acdff2a32f8c40707bf5a17b71ce86fb5ee9ad61690cba8f8227bbfc
-dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.gz=41f01647a80a7f21b85fe660af9e7964ad34f0e909d1e58c9e28e102a796791f
-dist/2025-04-02/rustc-beta-aarch64-unknown-linux-musl.tar.xz=8436eddf40ad5bf61153f24c887fb0f0e878bcc403095719b35f3147328d6406
-dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=07ee5588005a18477a7de89321e6527ee5f10af00e9c4eeb2a8c666f79d3d606
-dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=8a95664cef49c1e45b2ae61ec464a5be976e4cecd2b502a050f95b9eb25dd4c7
-dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=b9b186ea9bee58a646ce8c4c384fc4cb528c73c1fee3ea3f5028fd4b3fddab3a
-dist/2025-04-02/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9f62c2ea5b67c14ab804267d449ded07c8b551536886099b02b942ce2d641790
-dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=f07363ad0dff8b965dc10543f27cfd923266dea6284ebbb1d1b59b77f5ae2b61
-dist/2025-04-02/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a31afc234645a7dc5dc47f05bb5321fea12931278433df834def303cdea9f52d
-dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.gz=f396061e8faaf66edea34b0855e2d3760fc0fd5c75e99696b50b2d4f310e11e0
-dist/2025-04-02/rustc-beta-i686-pc-windows-gnu.tar.xz=0f95f9170c5b211db29c3baac9341ef61de83511fe0000b8aae65aaf90041ae6
-dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.gz=82b7d1136d1b6f3d229fc77eac19d2cbfb3a46de472345b0ec3ebc152872164f
-dist/2025-04-02/rustc-beta-i686-pc-windows-msvc.tar.xz=565bde72132e77617059da66edf9262f728336a2cc2c3c7cf4d61e0a4b5e681a
-dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.gz=8a3abc2a8aee8fa30699f51a216b29b41b2242143646d0f560f89bf72a0e285c
-dist/2025-04-02/rustc-beta-i686-unknown-linux-gnu.tar.xz=7d47cf99aa5fd3b5bc2caa918b4eaba793b6d38252a72fa7be631c8db27c8525
-dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=0654cf14bd3302d001fa00fe73cb7c597206c6897978b3aeefd00e9325a8bdad
-dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=6cd5c3ccb643a912d738239c0ad7464ee755cd81f45a26a9d3aa5ceeff569ba3
-dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3c0c5c52b04dd060f3a70b0c936dfb5c70ac29256361a491df9c898259dd551
-dist/2025-04-02/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=83a9bc8f9a61b2a7fedddbdfb253aa078bc9896f179ec9b1d1bd918e7de34663
-dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=21efa7a67647df8aa99e40317c798895321d09c48b8453e51eef1635c20e9c47
-dist/2025-04-02/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=56203ed9d3bbbab33e2825db7c72cfbe4f857f68dc98072cc98280cc4f1110d6
-dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=76c343aa3f5c74e1419e3f2f79dd3a2091fad8f6db644cf14f7aef036c8369d0
-dist/2025-04-02/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=e9c7b97a407127e51fa49ca94c5f22c59f2f325848d55e6160d6dcf7ff690f91
-dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=27935ff4136141519b4e7b37b55253960b7fa16f5cd751d731ed85019432247b
-dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=fd37c12a55055bc4a2f0e002b3126e6396df8d49254b2a8a7a45354aac46bb2c
-dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=cbeba9993d03c6c0c2c508414bee04665abb9c084c736b39c5b8d38c8f63402d
-dist/2025-04-02/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=e92f69d85929c81e3c91b2ab45eec418afc65edf6f8bf9383148a98b052353df
-dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=31a8ae1e64fb86a499518d7711595d653db56527aaedea06bc2bbcb912568844
-dist/2025-04-02/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=7d001ad6c4825d5323813ed19747cc3e3d2dcbbe76317329a52127b3de37ee88
-dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c69d15e75d51caa0cf77fbe149d43b62c327896bdeb0c6c73fa7240404289862
-dist/2025-04-02/rustc-beta-s390x-unknown-linux-gnu.tar.xz=cf80772ba9eed4885a28aab38323f0ed24ab220339a3b8a148b7c27860c48c19
-dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.gz=be22d207f8fd4722d69f6fdc56c57618ec01c54c5b6f3a8506c62583259d433a
-dist/2025-04-02/rustc-beta-x86_64-apple-darwin.tar.xz=04feea9824748ae01b4f4f85d15adc5baee23c996c22de86041888466ae69512
-dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.gz=8c75005f0309d30e7c272adce173adb253874ce881b347946b6ffe5a07067439
-dist/2025-04-02/rustc-beta-x86_64-pc-windows-gnu.tar.xz=7b87c4ab5291d9ad3670f4e9ee98fe9f6f877ab8d4952109d7e5e9d20181a700
-dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a96d89ba655db5317dd51ffa2ebb81b7bdb76b19cf12de36e9d0aba2c5877ae2
-dist/2025-04-02/rustc-beta-x86_64-pc-windows-msvc.tar.xz=84bcfd763eba610c78223697393ea97f1f70e567a44b8cfe22db79f1cade4201
-dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.gz=95ff7349cf12e49028256c06c8517719cada2720d4db80bfe7531289bbcdbde9
-dist/2025-04-02/rustc-beta-x86_64-unknown-freebsd.tar.xz=c8d0147c625faa5ce0e75c2509827bc4b190ad286e41411bce92023e00eb7a1d
-dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.gz=4be80235a110028d64404e532eb20af37e46db72a7ac3a0cf7c94ddf463c461f
-dist/2025-04-02/rustc-beta-x86_64-unknown-illumos.tar.xz=b18ea9a5c262c2f7505305110473cc15bd2c4ed9d583f07c15635406c050be08
-dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=234027a0075224ea157efaf39173ece43f9ca7d69d86e4790a2a038f7e6d98a6
-dist/2025-04-02/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=308a8ee2855a6471db3b3b64cb06e355e31d0d617ebc9f30757bb7db5f6fc7c0
-dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.gz=10f39cc94f39bcf17d0fa3b8efeb4db72408fba694e5eb0f175e7465f6d2de49
-dist/2025-04-02/rustc-beta-x86_64-unknown-linux-musl.tar.xz=6b0d16b46347fdbcddfafad8209df19515059eddce1e048ecf1585341fa1e586
-dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.gz=09f482425c92396f7e4ae3baf625dbcad1d886d82ecfb605b50393abdc23ce15
-dist/2025-04-02/rustc-beta-x86_64-unknown-netbsd.tar.xz=bac2f1a493bc2c5fa6cab1f58ff536cbeba55f77141b34636bfded9e3ff167b5
-dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.gz=8875ade1dd8ba0bca0c12860a076df1f089195a52adc546679025c405bef4dd1
-dist/2025-04-02/rust-std-beta-aarch64-apple-darwin.tar.xz=0a0593ab4c95802b0ed810c0442e13ad9304712c2f7c30a30c734523a7448d8a
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.gz=839086e20098c305adcdf9103cdf3f29a14c4140b4c1b728723e7aedad966883
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios.tar.xz=70f1832193e77a2018088943b531bdbacbe5404d5d7a34393e03f40329e742ce
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=94adeb2e63a91c09001facbc554678227a3717748104424e4fea71db3d5a16be
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=73c9bb75eb6fa4cf613c7a2b0e237472e144a1469cb043194ad7802052149fee
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.gz=0e01ed2620887b893687758d62422f661429e3c4566ff52d967463eca89f54c5
-dist/2025-04-02/rust-std-beta-aarch64-apple-ios-sim.tar.xz=c26beb8ea9f11845ce79d4f0ec2616ce82dfbc4fefadfc7f94a1df17f4d5bec2
-dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.gz=64047673efa9d9bad660e2a44f82e6f929c881fe205523bff10a549505d12b72
-dist/2025-04-02/rust-std-beta-aarch64-linux-android.tar.xz=0e4c6b76e8d92023533aef6fe377c9bd45ef9c1da517eda7bfefec85b966780b
-dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a25c50a86e5d674600cec5bd9e7939bf36b0afa766445b0d71673431388d285c
-dist/2025-04-02/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=8060a4c5337fa6c34b3f08ddb8886beeb5bafd2b02544b08a7cfcb466a27a972
-dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=efd76703934ae0187308eec9b3439abea0dd4437ac353d5dc07d92f9440ab9ee
-dist/2025-04-02/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=007462f554b0c6d2b165d727bf72b1ad4347a53869d672fcbf48db2c1dcf128d
-dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=e0dc54be7890edef123d2dc31f0dcddd1c807cc060a34f475093cab79100d9fd
-dist/2025-04-02/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=01c06c1d61c512a034a109f50f957e4496639549837b63464acb4fb24ff65e09
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=2042d37b09618379dd91125d20803e2d97d5f3f3794e01ed27597a0f3b27c102
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=568f0b8da190daf78cd8573b0408db2ecc2c07b1cb1fa463239581963738e9de
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=386b1e4786dbfe342626cde4c3708abd04d9862d69717c7acd5dfe82427e38f9
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=781d0f9417e1b3d33d95e3c5b82ba7e481a610dc468345119e09a52b1d170045
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=8673d059524ac141a8907decfda36c8afac81fd36dd75f78df750a6d52ada221
-dist/2025-04-02/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=8e8afe45e9bb84ebc3e02f0b4b71dbcec7c844128329d31067303b86113c3439
-dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.gz=72e1dce3c1f821b6018ec155bff250b941afcfcf1697b440a69822b10e929b94
-dist/2025-04-02/rust-std-beta-aarch64-unknown-none.tar.xz=7030883ad3ca170a061972707c488fc25d4dc8ab0f60a1b9b54240e42ca713ba
-dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=28f87a505ca4e2c33015338d73cfdf5c2fdb1f5775f82ec432d033a36880351d
-dist/2025-04-02/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=45669a09671c183d702a31b6ecf095e8f422797c4e242063c7864180c6f657a4
-dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.gz=1ad54cabda8bfabfd93e16c564c0950c26e1502662d5f4ce3b33b4ee265b9a2d
-dist/2025-04-02/rust-std-beta-aarch64-unknown-uefi.tar.xz=a79f9d7eb4297994b2e87d48106a959c82bc4387433e5e86dc8caddde29a8a4e
-dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.gz=75192092fa7a40051a70a843cf75513de2c50d66927f16b122f7417c1d4f25e7
-dist/2025-04-02/rust-std-beta-arm-linux-androideabi.tar.xz=843dde45dfa49b5cc97266c61d8e58dfb22dbf2288e6e8baaef769eaf59675cc
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=03ccaa5e246502fc61fea1e0b33f5c60b5895cd0b5b932bf640d62e97164b457
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=a73525dcab3a0f3bc7064c8a6cdeb9b0e5b359501cb7e8fe20075a0e97b2a5ba
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8c851fc122d14beee962e15fdb95c2873769805180be30723f418d84cbc0a8b8
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=8524ad1b7723a4a5898837d5b526fb11ffcd039b2c4835a2e139071f6cfd4e9f
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=b108ec4460d4f6ca79813e6d2d4cb7061fa522a990333fb9f4f927b0fc659624
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0bdb617dfa833c62c03f5bfd2f06ed3ca1479908d860f888d661794188bd57d6
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=19f9fff71344f7a42f958c3efec720e4b2e0d67ba36a5fd66946e74811259f2b
-dist/2025-04-02/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=0cdfe9b4a8bc4b63637cfd9766c3e0e1d3dcd6d2e82fe35f57973a0081e630ec
-dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=a8490374598bbfa42931bbfba51ecc0186c476217eb79408ae6b80a4ba6de9f2
-dist/2025-04-02/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=2bc2838320667f060c140345d1c26aedf90bf5efb1f72e6722b74d32f876901c
-dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.gz=9a237e1dbd2e3b555aa3932351d1c20a0f9f2f06e810abd254b5ca152aace687
-dist/2025-04-02/rust-std-beta-armebv7r-none-eabi.tar.xz=f4978bf9af719f0b6e8300ea862fe617e983e5443a46c769d60d5e8c4d556ba8
-dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.gz=c1476718625d5d5d42b60faa9ade845272b0b71e91d77a9cdd271c4682c900d2
-dist/2025-04-02/rust-std-beta-armebv7r-none-eabihf.tar.xz=f8ab07e99983fc7395841cc9ed7ce7cfaedd87bfb91214bd83508ad96aef0c0b
-dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=649071a7de4792ff75da59ca421ea1cb364c011db97e73c480982a5f9f06b8aa
-dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=529aac0b0a385fa5ddb76a88eb6923bcc981679caab2d1c374d443383c99f52a
-dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8bdf3412b0b557485099db86afcdf58293bfd4c09c4b360c2d9733788b612122
-dist/2025-04-02/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=5d5a4ebed984a0930b214ec0b11e20fd9a7b8d5dc2d00985b75a77c8febcf441
-dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.gz=2c03cbb393641876bebad9b76465ac7f96adb82c14dcc9b5bc01a82e5110b892
-dist/2025-04-02/rust-std-beta-armv7-linux-androideabi.tar.xz=67d86fa728178c30cd7a33e0c488c32f58ae0caeb9a982370e080ea38853830b
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=3737dd5f80f35f3fecf5cd8324c9226f45bb0bfd040998d91509a2c6fd8967f1
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8f9f710c92af058d5a07c93b4cfd45b7d30e63ab79bea7f79530537aae2dd836
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=6ecb3e238e125e88851dba9711b2b32f4de1da55de36a62373bfcc42d001fa0b
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=7d6807d24afe4825b77c1cb74c1412b814cf2508f5b40debb55b3f264e02eb6a
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=a15fccced78065f748a5c4f66763b8940ae3e52b5048b5ee1fab6b0b7b40c701
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=20bc43c1b5742a9c7a97ade055441ca1ca153dab9602db3ffaf1ac518713568e
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=b01929a0f18b1a41b65307a04d1273d2197df83b3c124f80659ef8fa4f8c4577
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=2a13350da7c632d3878ca8da8a7d0bda60c850df8e5d824956082b524eb136fe
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=11bc9fd437be07cb454182b0d7b287ec030f7d8904f096b73beda6480ba33285
-dist/2025-04-02/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=31e06feb45173fec8e58cf92216e44d556587fe2ed866102206e23514c73d3f0
-dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.gz=aebbae792c070adea3f10135c02b2cf5d623b84e765ec3a72c89275f53a85384
-dist/2025-04-02/rust-std-beta-armv7a-none-eabi.tar.xz=e80dcb152e7a8337fbbff6a5c8dfcd9c6da4b753da6b14e63fe7c15cc0836359
-dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.gz=e79846c1203d5d375c7c1cff1c843cb6fcd4e33bbc71b2363e12fc900bbd72bd
-dist/2025-04-02/rust-std-beta-armv7r-none-eabi.tar.xz=0e24e48461cc46edef0237e38480ac806d0521c73ea366668e731f29b638d7c9
-dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.gz=fd2a9b48ea203b44567cfdcfcfb21d5d803896fdfdc5f3aa191e3fa7472b98db
-dist/2025-04-02/rust-std-beta-armv7r-none-eabihf.tar.xz=2b85d461bed34a97cf832a7c0e1d4179d7800ef47523a8e31d635b8de5dd44a7
-dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.gz=cab412c30b27060cdcb29adb947dc070875813726707dff121c4a1aa8615646d
-dist/2025-04-02/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1b8d469fbb8903a5f4f5eb6ccee7bdf28cc56137b6b212fdfa1aed647f4c347b
-dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.gz=93fa0383e32f18567c3c156f3cddde1fa4296003f98cdd22b0b5628d69d5208a
-dist/2025-04-02/rust-std-beta-i586-unknown-linux-musl.tar.xz=71ae00b01ffbfdc6654d0fd14df204adb7d499ac71e59c93affff91d58833d88
-dist/2025-04-02/rust-std-beta-i686-linux-android.tar.gz=4c6f4764e284ff29958417295ddc5d3316072fc9eac87dfed8b694c237aa4f88
-dist/2025-04-02/rust-std-beta-i686-linux-android.tar.xz=f471a7abb2d447f668f01973be4712e20c6dd29b210a96517b277e62c6d7de07
-dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.gz=0c5efb9792502fc08174b2556f5c91f3edbad6e02de5e230f39c5fa011fc935c
-dist/2025-04-02/rust-std-beta-i686-pc-windows-gnu.tar.xz=b6a87360e7be832288e59239d41e809db01710ccae5ef37bcbe7b0eb1d311e66
-dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=0429745cd95a198a7a42a1ce0c7ab2d502f3ff3eee81104fe6d5d4d5dab9447e
-dist/2025-04-02/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=bcb43c9e2d4a49c18d39e041d28021f2302707ae9ac20ef37f4d467fd2cd3975
-dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.gz=e1d8c40e61701c6bfd519125169cc1ab1d60e9a58238351bbeda0ccc5522cc49
-dist/2025-04-02/rust-std-beta-i686-pc-windows-msvc.tar.xz=1f87f343a90f6e88cb3173d52f4f88d8abdb0c1a613681c92675c1acc340aa54
-dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.gz=5862f33548bef1aa21b3d63caefa12ee34775cb378f89c4dc161e081a773d11e
-dist/2025-04-02/rust-std-beta-i686-unknown-freebsd.tar.xz=ed3460948031d0c4e97f7b1b77062f388d133db2b2212518eabd3198e72c031c
-dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.gz=3a6edd9f412a274e372c9555b6758d540d06ac08efd21ce95df1ed4d30418afd
-dist/2025-04-02/rust-std-beta-i686-unknown-linux-gnu.tar.xz=8338baaa50b9cb08a28f7bb21a22deef849f8809282c661e48c486a168b6249e
-dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.gz=56ab80fc6cb75a0d66c477e76f87918645bc3b616cf704306820832681022768
-dist/2025-04-02/rust-std-beta-i686-unknown-linux-musl.tar.xz=94efb810dbee977ecb3ff5a42a5a620d720c237da58d974ba1f376c99947baf5
-dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.gz=64cb107065bde9b30c78b9b342211c4e6cd2c3ed726155dacfcf5958ba869a82
-dist/2025-04-02/rust-std-beta-i686-unknown-uefi.tar.xz=ff1bc215b4aba25f59eeee8285967e24b78f6965473ea8bb30186ab55804f88a
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=da1d33b266e1dd277f97f63228843765706f26c9f75c4b5171f49c2762fed870
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=8309c9c4a03df90eb53116b5c5c4870d103911227848919580a48e5e85954709
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=26a3115d5354f878f80bef1c83a44af185e2780882e17143ca57aff078d123a0
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=12431c3b50276f352a3ea71c74db279cd03c2edfb3edf743f81774d4274f7ef9
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.gz=ac67b23f84d09ab17d26f30deb38a128ccf812a561738327effe48ecd0caa319
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-none.tar.xz=5508b02465d3dbb40512a142eabb27817807d2af153089f7d05a0af355fdb245
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a79a59139e13166cb1121d703cee113bf92821f937d433cb9a2c00567280a4e2
-dist/2025-04-02/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8c3b5501050f57125cc89e6525b780ca0e18d2d5318f779894ab97efef761fb3
-dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=84a48148eb313f236f85a4907af615b7af4c3ce3d9065ffe0db54458852690ab
-dist/2025-04-02/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=26281622332b438bc43b8f46921153a45c6236a4c0939c76fdb4d9fb3d29cbbb
-dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=0eef233c871404b913c6458d8005d362e3c24fcb0670ac49a7e67b1a503b4b29
-dist/2025-04-02/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=b96422b0f33446abee203160a22e9bac8861e1c7988b2cef463276743001fc7c
-dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=18db97406a6e644734c7890991cb3006fabe1e1a185f89d108d28a992ed7c17c
-dist/2025-04-02/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=eea42655b5335643905acaa3d8ff1774e2c1a39ffde363c2073a8636c153087a
-dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=5feaf6f3859204979fb4dab03fc93428abd103d61822d6e4e9a2f5d6d155213a
-dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=98f8e695253c9dad3d82638bd69c084a3e7a96d17eb1dba0f90a42df993de864
-dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e028f2ec967ecee5d9e7b48058209428ed220c5da2c00f2753f8d4e98951e168
-dist/2025-04-02/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=69f508ffcb55347dbb773cfa22a1f7a6362f3aff6a48296b50945422ea82c7b5
-dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=ea30bf48fcb3873db4019ae3d248e1db868e1f7fc49e4549737aae58b3b49b22
-dist/2025-04-02/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=c3724aaa58f812dc8283622f27e215546d8522b6ecdf1d191010dde3a1ba3344
-dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=9d24eb785b66796309c2f03944719fb6b6980ae8fb7ca97084fcfdea0094bcce
-dist/2025-04-02/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6b2233474eb64d041e6bd8f1b6dee3eaf775b6b5a7ddec703689352cf88f6a2
-dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=8a5c94055180b9a1226a23c5992a622062ac52cddf91651a91a5d236be46d0c8
-dist/2025-04-02/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=7ea826d6c58fe1ef1c9374aef0cbfec5495daddcda581b231d18397330d9e248
-dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=811881bd5b514c89c316453ea1214fbeccf5388f18468cc83676a879d58f53ab
-dist/2025-04-02/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=9448b7bad586237faa4f090ce8c3de83b62d19fbe37104ae32032d9df709d2e6
-dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=dd9252a03b0a888ee7598a84c20aac721739c2caf9c5b585274d2a30d7fcbcb6
-dist/2025-04-02/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=d1f134647fe0c3efcce80351cf9e4786ca8e3e336c0316b7c28ff07b78907c73
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=4f688c40457ba71542438fbc100b62b5f081435567f965512481ccf3d002826d
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=a474fddf29c6979e0870c397c19f64de00650893a781eb51d9e136802bfabbfd
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7071209fdf0d2605b623ef96c934ed039d1dd95a68c438a8c563530ed48fb4e2
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=1328504e895dc9bbc36ac697bd5031e0034b2468fc66a91e42b39a4d35d4ea8b
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=e7878c1137279790205e62f9c363a6f45e2a8cd9c30702a53478a8104dc87a6b
-dist/2025-04-02/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=f373b1d79547c385a01c2b36951eb3750a4cf3bcaaa213587af9a6b4274dc924
-dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=4832338ebc25d088e30952605b3f6491d96003790df5b10c5c56e29ec69ac646
-dist/2025-04-02/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=d782dac690b3da2b96206809512f1ae82fb4a73ee387d91128ae0d98bf51ef3a
-dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=faccf22845e31101a420796d9065b350092cbee29d755c2369ee36cc7172866f
-dist/2025-04-02/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=f296c5726380b1f2b8603a079e8dfdfa7e4a97a499b1e86874753c312768ab15
-dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=b8a8fd8fda8b99d96d6f890bcd0c9073393441e85a4cda169b6fc7dbb7296984
-dist/2025-04-02/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=923a0530224f0631162f7b86bef79be85f45071f62ca4f5de0588fb5ca6affa8
-dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.gz=944a83365d3c46313e28b1d3a5b0e52e57ce88b3eaaf0f7f53234d4423ce9ca7
-dist/2025-04-02/rust-std-beta-sparcv9-sun-solaris.tar.xz=be0c983c443f05feb4614d97336755894b3ffc5083d852bd84ee7cd9e5edfa03
-dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.gz=08905a766352dd259be919aeb366e965dbbd4066c398dc4d26efa333b0ac46b8
-dist/2025-04-02/rust-std-beta-thumbv6m-none-eabi.tar.xz=4fa005107c3d1addb242179c03a804a27d34ca68bd76c092a41a197da56abce1
-dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.gz=e6ccc1004004ed759b1814daae0b50a3a0adca9786688ef9cc601a0a19edc72a
-dist/2025-04-02/rust-std-beta-thumbv7em-none-eabi.tar.xz=fc23abf9c086a34264bfcfe7c4876ec65ce54f8ca73a98020bb8eab6d2c51d57
-dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.gz=e8121551c0529f73796bc157bf916e3608685454a02a81d170a258a7465b5b7c
-dist/2025-04-02/rust-std-beta-thumbv7em-none-eabihf.tar.xz=2695f76447ff5d70aa3cc6b6690267b31b9aa4ddc7c45205e529f92d234483a0
-dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.gz=36d7fb4edd572c7d73501aab7c89737ee0036d606700c728f430142e91649eb0
-dist/2025-04-02/rust-std-beta-thumbv7m-none-eabi.tar.xz=a6e59eaed0ab3e310852d9a75fc43600c7c2eee0c808224b87bcb8c18df4ada6
-dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6bc70be43929b77f3508b1872e5b09227aebce1c7c9c943995b5df92cf6d9181
-dist/2025-04-02/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=37b956924534aed1ae7ef9908d38bf724c6903591269136d23e293e17a0d333f
-dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=041562edada0caeea67fe7f3ffb5b9f8c1b506c0d5ee7b657c5ee2afbefba7fa
-dist/2025-04-02/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=8980372a7e9a072b1e0b954569e59df260583a3371daf005c5a83576688562d1
-dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=83f461ac0ebcc05d5cbf67a6585b49dc7b245c8788dc3a75e08a93be41e2615f
-dist/2025-04-02/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=6ac8847ce601c8dfeffff07915de06a605b3c685f81b90f87b092897c2afb973
-dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=bfcd9ff7dc9bb5e95bd563d750240efcbc3bfa1a21a9f9a2786ef37f665b7e43
-dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=4507383395a26d41abd71041b162dfc5e9471a4c624d9fd6ad310e184ef15d01
-dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=b4d1940ea5e24cd6a0ba3906c98d2b03e4a18927619152b43e91832733316258
-dist/2025-04-02/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=45eec7770344beb84cf418cf7818216d123136465785f4742127f6f5a8c5ce27
-dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.gz=19bf2f4bf64f874ccfd84b820b7200e83e896c96a396edd7bd10301d2bc89d98
-dist/2025-04-02/rust-std-beta-wasm32-unknown-emscripten.tar.xz=4c616b7bd972c09461f0bccf5009bc574dcfa8bdce2dd97d17fcffd64542e496
-dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.gz=69bcb61fd0f8bd7d2da225a4525a877cce003afd7fc3d789c385f164959cd41a
-dist/2025-04-02/rust-std-beta-wasm32-unknown-unknown.tar.xz=0372a64eda0c7249ce5fbcbbbf29e145e969b383a73b7c470f0b583720fcdbe2
-dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.gz=f76a2a3f4702eb781a680ebd4346afb4c26ca2235e62bad144b057860c09b8a8
-dist/2025-04-02/rust-std-beta-wasm32-wasip1.tar.xz=173bc3317b59a01036a9c8e0bccc570fd6f5174d15f94634f53d81dec3d2cd68
-dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.gz=18e05380478ed0b3f76d9062fade2be2e66c039dcc470ffb01be3c8dffc79995
-dist/2025-04-02/rust-std-beta-wasm32-wasip1-threads.tar.xz=3d477eb85308f73d1081d6dd3e54577be4bd84f291a50af0e3be15fa8aa36db6
-dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.gz=3444883960a9f8b831d1f26ee17ef082a2029cdc2e9b45ce5af4d6565d3a526e
-dist/2025-04-02/rust-std-beta-wasm32-wasip2.tar.xz=867361c7ba912b404c426807a60625a1f830707a172f7da139c1a892aa85bf35
-dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.gz=d15017a323c662a1e8c65f51e66151138c2255cd8842a67e990000606dac839f
-dist/2025-04-02/rust-std-beta-wasm32v1-none.tar.xz=f3b32484ef287317187ca0bd5245b1793ae40d50290a2882419da8503b8243f3
-dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.gz=179be6a29fcf16b4c18775208569a051f2f5a38558e751d2dda0a42027868843
-dist/2025-04-02/rust-std-beta-x86_64-apple-darwin.tar.xz=912f7f8d7117a5cac85dffee5ffd9f2c1cf237477bb0f9e1127afff1f0cd4757
-dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.gz=9d2f3230bd82ba9d45e572b45ec63c63cfb592dba6311b6a16de075f18c86999
-dist/2025-04-02/rust-std-beta-x86_64-apple-ios.tar.xz=c8ff77db2d081444ab5167764465beb33046cc81cf2e8dbbd8e9a7328306762c
-dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=76c9b2ae710fed611a2294a5e4bb6597b07d78f0bbd3a5a0d15c3320f38a0017
-dist/2025-04-02/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=b9c485a3824c971a42c10af26cf06c539c34fa429e92601a1978280867029e62
-dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=a223c08b88c768d97bf9f071c74d9548acf00bbb097b8c8427c2ec87ca205597
-dist/2025-04-02/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=34ddb3db8a71edabb4d0fd8d52a164dbca5a5cd96d6ba131e7d439c333726f78
-dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.gz=9ba28bf95c75ca0d69461d1c044902443053b64678b540967a97c7cd2eb7cc4c
-dist/2025-04-02/rust-std-beta-x86_64-linux-android.tar.xz=09e35188a801371a55abeb9e2ee455ebd26d41b8eb561b8016ecacfc7ba20c90
-dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.gz=c1f2fb4b90cf258dfa1a52167ba925b583dc889ec1c3c48958560ff3b7b79b13
-dist/2025-04-02/rust-std-beta-x86_64-pc-solaris.tar.xz=d71f2bade21f751d9592e865ce3722b5d3b9abc49e55ca9d04c02d658360b6ad
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=691c23504582e6db1cf883f52b5378aad3c42da7e2d2237e54601be9c8d16cac
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=22e7327c5ba22863cb62cc5331862b8c2b4b10a732637729b5e1504034aa2cf1
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=81b7dda817a7dbc8b33542c356e0c5e5605b7c60a2fee13f4a266c8d970a3f54
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=09e4c9804f7489b337ccf66426e18e7522dcba24234b289a39eb63c8242353d0
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=a8188567321462309fb63af38f652c6a7448ebaae1425b9ec20d2fe2a12e8896
-dist/2025-04-02/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=5284f85dce61b2b021888b6b82995aa7b4a14a979b42b83499a810c261fc183e
-dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.gz=eb57c8ca7f515386d60a88e56443e377aae70e185ac52a62869e115c636a2bcc
-dist/2025-04-02/rust-std-beta-x86_64-unknown-freebsd.tar.xz=8bef59b74196fa9f7839bb491f6b32d0761a45c8d7178980ee3afd80231b836e
-dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f43f402881f4558e3df4a7ace68ba80caa9354cfa5a8b1efac89f95e38386253
-dist/2025-04-02/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=ea7d09c015c057591ff51b808cca9c8c1d973de3a9033fe42c1bf34d748d03a6
-dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.gz=a4835455348bc5b154b1bba63aa03d2294713589214b50d3babae3e0f9918a3c
-dist/2025-04-02/rust-std-beta-x86_64-unknown-illumos.tar.xz=711920e7491332251fb672abdc7685fa940f863d8e182e2ae9d9347d7fa6a725
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=1b8324839c0e10e410f29bd471f6c49eb4710adbe172d6bef3e619ae95d47d02
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=223b41f16a80b9c404f5af9a194b7414ef354681f911839353f24b44eed91494
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=6d8d8d9fd6336de0ebcb58fa85aa0d11e62a60d6c6ca01d71da0bdf668d216c1
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=033df93011b4461cde64c4230c495bad1523b9b38f5b0de56dd928c1da85b577
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=70a441c0cf8ca25abc1f722c1db5dde8b5fd3b90c767895b7518fc58c2678390
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=b5584d6d0031f8230a40f5ed76570ab1396c8997c3e957ca159d72a5dc201a2d
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=2596cdc3708d82aa93a8a1f595238fe9fd7b5b05a4886e7e390ca3b86d352e7e
-dist/2025-04-02/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=c03901c0c8434b5db244c22145870e7d933b9060af3b23f24a765c755098a3a1
-dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.gz=82bc22594dc602b27edf8233bd9c4fbf0323999ce99ff2a7ddd0ce9268647eb1
-dist/2025-04-02/rust-std-beta-x86_64-unknown-netbsd.tar.xz=86f674f5e19a1b1780f06a6d5add06fd4240430233b7c3f5203a4daa5f444673
-dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.gz=ca7882354f4274dc405034aa6edbda685b9d76bc6e5905074d2aaf8c35b35a95
-dist/2025-04-02/rust-std-beta-x86_64-unknown-none.tar.xz=ed6c828fdafcf87a68f522379f11c44eff1a4be1bf027d9888d1f17f22e9ca61
-dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.gz=6f8ab182274e2f5b0fa82fdc5c6e3776ba969e6ee6f6098ce6d170f6685f55c2
-dist/2025-04-02/rust-std-beta-x86_64-unknown-redox.tar.xz=ee061d725f657a2e52114f282be0cab1a6e542a0270b11782c36e8737ed84f32
-dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.gz=0324f537f463738bbdbf40b92423df6c6068f76c583872d6070d6a41c5169dac
-dist/2025-04-02/rust-std-beta-x86_64-unknown-uefi.tar.xz=2cd2727f71b14c06eb0a14fa532e5b3bc66f8b983c021f3201c327606b04511e
-dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.gz=76010b5a9f8dff0102a18de75e818c51b915a3bcff428fc48973728577c2ecd3
-dist/2025-04-02/cargo-beta-aarch64-apple-darwin.tar.xz=f0f03ece675cfaa9dd0f00204d7ddd4086a45357f09cac9d800d37bef8d0db33
-dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.gz=bf4ab12afcea7911ab973177de83b7bbdfd0000e3090331f31a595d57819ed6d
-dist/2025-04-02/cargo-beta-aarch64-pc-windows-msvc.tar.xz=156fc94166e5f2af91fd9a36c67b545c0eff63dad51fcd81571cce01447c1c1b
-dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=c86bbf8091188ab9f7d41e566ef628a657d66683884333c3851e99edaea6e279
-dist/2025-04-02/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=610383a4efb93ab53cc747ba038888742346499407c982b7bc8c0c41689cf453
-dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.gz=7d427779360c9cba5903c2a0183be1c1759cb2c2f2b77bd2f64b409821fabb64
-dist/2025-04-02/cargo-beta-aarch64-unknown-linux-musl.tar.xz=29bda8bd7dcee65315b8c14a527f4e4b4dd678b35dd430591f7c71712ecbd2f9
-dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=ef6d6a810eecb3a38940634b653257070dcfcff52c2d8321fa3a933d41c7ed73
-dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=79796d83949811776aaedc7e6db6d32374c07b8f8d256d9b871de335bf5e7074
-dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=fa93a1285a97453e2aaaf9cf392abb4ff9a419451e925959470166522e54b1dc
-dist/2025-04-02/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=acb69df00475904faccf18729030a70e8ce21543189d48c7102330a98a12edf1
-dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7141bf32c173d26f34571b2dfb890187d866f113e28b63908841377e48dbc6ab
-dist/2025-04-02/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=249f3c535805fb2510d13338401e9ae96f16e6996e58551025b35676a1147ab5
-dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.gz=fe4f5f35ecac25bc3726ffecbe3e650d51adb9ea13dc5153a0699ea8d8776d13
-dist/2025-04-02/cargo-beta-i686-pc-windows-gnu.tar.xz=b7b8432464eb793e9a651c4c38ee8abe76421a9be7f75e96237a4ef938f927f9
-dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.gz=a283da65d3a75435ff3d05441fd0337472fd16325531086e90b01cc5d5bd221a
-dist/2025-04-02/cargo-beta-i686-pc-windows-msvc.tar.xz=ae19f98c901228ae5c7573cebde4816517bdb8d03dbdc7b92d95518d27d93531
-dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.gz=e3c5b2560f64c8056ef82ed0cd659d35fda5181f19fa670b962228142398efbc
-dist/2025-04-02/cargo-beta-i686-unknown-linux-gnu.tar.xz=3fc435b8a186f6ec1b7ebc38c92c2e23e1bd786415fc33e7743ef95c37c69b45
-dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=bcab46663be61e979b7a89792d164e182d5482ad9b444a969dbb304c5dad8c8c
-dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=9e2ecb90d85a4aca95211892a6a41fde09ce1e4f44a60caab9aeb61833191d36
-dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=3c5c40f61e85663d03fe51f63d505d8dca73f94bfb3eed29f6e1396b31e0a554
-dist/2025-04-02/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=775c56ce638e0923758ab5f82a87c15b7a1500d10e0be2433af40364a0455d58
-dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=c1a144dc83b673e0375e8f718cde6672ca276dbab9161d7f3e002c6273352c1b
-dist/2025-04-02/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1b41b3396340c97c122661c95fe54265036e721f1750bad3a8fe4920f6f52b34
-dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2a43a7682ea3da8b911b09a7bb4a3a75fc3facb64fc952e51ff35c63e6630b75
-dist/2025-04-02/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=73a3383196527e63716de1b1cab233226519873556a755a7e47279f799936116
-dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d5f521839bd4b258454097cf97b056508e6f9103f7312c93b632ae44ac9f7dc0
-dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=c4fc5ff91bc1054e8497efa53ee6a9a9eb7f06927cd314a681e16b6d46b08440
-dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5b0d569fe4ec84d6e7526af9d9794b440e8f1b5fc1b09e951678b09fd3ff97fb
-dist/2025-04-02/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e9c68eee5763c624cbe312bc1b50b6c3172eb7997e209371692e7f897d13b03b
-dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=96962461e7f6744a46f18a557a4701d35d6fa3b6d960d854f4c3effe6f2636f8
-dist/2025-04-02/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=4d6029204f930543afeeaf44d9e635692c86c9daaaac6301cccbe076c7facbe5
-dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.gz=f40421ea02804c3089420e5ca13838f94fb89c114de9a9e596e9a1207d2166d7
-dist/2025-04-02/cargo-beta-s390x-unknown-linux-gnu.tar.xz=77521eb215cded6886267644661b3357590f20368383f314da8f310197e9679e
-dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.gz=0357ed5c9c8ccbe71f89695bffe1604dbd2f451472fc6ea8d8d2dfc93a703b30
-dist/2025-04-02/cargo-beta-x86_64-apple-darwin.tar.xz=6ce4f66b60609f58046138831ae3828ad1d58f8d0b2f515f153c96b690a0134f
-dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.gz=8fbf8506fc0c47bb30043c026107c51d6b548fa91320b5bbd2c608e191bdc007
-dist/2025-04-02/cargo-beta-x86_64-pc-windows-gnu.tar.xz=bb57df35e6d73b0b0bba58801d66febfed03f0b3f74085eb50ef8b5ea3fdbb40
-dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.gz=0bec5e9059c4b3035f636017c1586653d372f03969bcd4d80c0eaee52f01a2ac
-dist/2025-04-02/cargo-beta-x86_64-pc-windows-msvc.tar.xz=3f836d3027d7ed25655f43262b126311bf014629dadc4a860f00302bc468e752
-dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.gz=0f60566416471c38350c12f066bb512eca65a66319f5ee7fdbb60464d70661fa
-dist/2025-04-02/cargo-beta-x86_64-unknown-freebsd.tar.xz=eae168df54ddfe95db669c205ae97baa902056722856fa174758ebd058168a95
-dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.gz=816eb91ac3858043f58075fc48fc2e90d0427c58b6283be589d337a7f0ddc9df
-dist/2025-04-02/cargo-beta-x86_64-unknown-illumos.tar.xz=faba548d376309b71bcdae49f7089705be951f72a84ef68362aa6d865d40ebf9
-dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=1fe7e9d2c5a733acdaed418011c1fc31c3036e5299e8f9288ddeac43780fa35e
-dist/2025-04-02/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=7a39bd08e46d3e19da81c02ea3bb46bd1750a3ac1d1db8fb5db852cde14cdd72
-dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.gz=00df62b75e1811fd4fcc827b531e7ad94a73fcc37318d0aed28796d902b33568
-dist/2025-04-02/cargo-beta-x86_64-unknown-linux-musl.tar.xz=874084ab37814ddf50ef423e22f0721e5c24acd953ed02cf83432d2372606a5f
-dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.gz=7b4467e398bd34f94912c56863ae83b45415bbf612b3be15624a6a410c27ff2a
-dist/2025-04-02/cargo-beta-x86_64-unknown-netbsd.tar.xz=75e7ac498a8e617bb907c26f2a3bba9a1e9a22af1c0946f88c7bd53c28790ffb
-dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.gz=0f5a8a6a96b8785beae1fc9476374d060632dcc4c17a4335031425ee8e2dec48
-dist/2025-04-02/clippy-beta-aarch64-apple-darwin.tar.xz=aed266be1799ae3e95099d491c3b20b731b2094bc8388c6ac3e782667b58ca6f
-dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.gz=0ca97501432918d43aa9bed9b58cd4f1d0d738970e09d6c037ce967519b2b13f
-dist/2025-04-02/clippy-beta-aarch64-pc-windows-msvc.tar.xz=c64edd87358c1ecb9e01b204977edaf0307cc939a3dd3ae62f151c153ac2019b
-dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7bfdd371ed44a32e50ecd6baf107796d5a77ca3cce0bd58bc5882afd98ca0edf
-dist/2025-04-02/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=cf49acab8153fb65867a9c44eabb7f156f85e9818b6f49453067ce0764036919
-dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.gz=bfb20f832ba30a4840f0d4898d27cf69b5717a78bd71b20270f8ddd66c48bc69
-dist/2025-04-02/clippy-beta-aarch64-unknown-linux-musl.tar.xz=54081690d35c39267a49d991e5e0c16043261b6969c49f23c2be44e46c3bfcdf
-dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=3d88b69d6c67c58b09be9d679cfbe8ee449b9de419e950edcffd4637ded46cac
-dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=67843ea0aeaab167029818669074e8bdc46a7e1c269a15580cdfe44a7d2ba96b
-dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=46e9efe50418a035ddabf9a6467b6b0ef20453816c4b6dfd46fa1342bdc42167
-dist/2025-04-02/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=3b27dc434e88280bbc89f5c5ba6eb68ec5332b549b73f7f8d79feda9cbb49628
-dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=670a6ce01ee6e5225b152a1357eba9a41cb47f04d08cdc8a0828eded4132aba1
-dist/2025-04-02/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=cf92bed8c784e9579c09305fd227df3992950c227bc844a9b09995828d62e2cc
-dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.gz=58238b6f4f8ad957a39c0eb63b45007d1c3f8c79e98307c7e5a531b7309a30f4
-dist/2025-04-02/clippy-beta-i686-pc-windows-gnu.tar.xz=e77c5215b3e96c59fa150330cb5144db66dac377fdad3be9c28f9fa07d9fb7cc
-dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.gz=7c65df8af1f6f4102ffbd7fdaec50c24f89f2631edd06642732f1b5c74558ab4
-dist/2025-04-02/clippy-beta-i686-pc-windows-msvc.tar.xz=eeb119d26e1e2ddd3ef72741158d75d0db254f6420fd729d34abe5d172c7d765
-dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.gz=c43518b27adce17f06f89c70ab52ae4c94f1f7129a182c16f9bb28fbc8a5f40b
-dist/2025-04-02/clippy-beta-i686-unknown-linux-gnu.tar.xz=1d972c55d89cc01b7e408b4e24e8975bca29ff28578f224024a00f00d17c28b8
-dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=0d779bd9fcc5ed8e1db81a3a385bc0158c3903e5b0f0e4c99d172eee106a4f3e
-dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=5515e0678c081ddae45f3f0c3c7ae58cc2f7b1141e1557a39826bf1aa58a2480
-dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=e99599c1fd0cab2eb0e89dd8e37e90ee2106d602a3edb3473fd65768bb8f7b27
-dist/2025-04-02/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f346a801dee3734461eab4303469d31faaf3e8f0d733b854470722ed48c66276
-dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=cd7b58e507d6695ada446ef9fa113a9588501832f4627b3e7cc0000a77c9265f
-dist/2025-04-02/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a7073874663b4ce8eb47a0257ac0cf8049acb34703241466f1208489c4dbee0
-dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=78d0b9581a7d79549bbb6a7e8984bf923a7b80bf6bb3979a90e90ceed8e66d33
-dist/2025-04-02/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=79069a26ed617a2a07eef7cf098d028cb0c172fc4a6dc99115a51862b1b8bea8
-dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=23c58421839105c88937ad90a92603b7fcd6d9e21f291ab8c419fce1663a20a5
-dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=b546706d28c46f5bd3799d6b42201962ec2e9d6baf8df2b66cfcf1bc42789036
-dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=31cf0d973eb3f0ca341a8d64c26b8b3b045b44b3c00d2497893dac6e44ebdeb4
-dist/2025-04-02/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8afd89866c41631d4f4ac4d8a06d943473af7a96b043f6112216a04863817820
-dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=f08bf4ed1519e7c47f354a0d0b750933342314bacd4be761746666cf455cf74b
-dist/2025-04-02/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=e502f83f811c35e43df0a5e158d9eb61f60c9e1aacc75b588b2ba85022ca4b3e
-dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.gz=21bede57083544028238ef6c9d24cbf9194a35c88500f2d0c5d50e6f0ae79616
-dist/2025-04-02/clippy-beta-s390x-unknown-linux-gnu.tar.xz=670c0a293e1b01f331c2645b648c1df087da4c1b5d689f608279b1ba524cbaef
-dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.gz=a6552e032c047203d5a9f5b767945c7a556be35468c42631c0c84cd049e24a8a
-dist/2025-04-02/clippy-beta-x86_64-apple-darwin.tar.xz=17a9e9ea8e0d6140080b7fa4e3c77ad1a7fde3c3179f26b0aabe34c3af73b58a
-dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.gz=2ffa8663502f4c6bba049318c70e79c174fd717d45ab4427103fc11563be678f
-dist/2025-04-02/clippy-beta-x86_64-pc-windows-gnu.tar.xz=8c0a71f226b229f30a9acfbc1ab7c6bbedf692ef7b26737721a0518d3f1972ab
-dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.gz=463c7a5d2a11beaeb1e63bc769db89fb9996a0558da15b4e091befe982893711
-dist/2025-04-02/clippy-beta-x86_64-pc-windows-msvc.tar.xz=40241fa6e463df734096e0e910b414c83d8a4dc8706b7c712cc170844e59e3c6
-dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.gz=6464044b05b326d8ea594a963e38a52a1e27e0f028704427c41ec5e93e3772d9
-dist/2025-04-02/clippy-beta-x86_64-unknown-freebsd.tar.xz=77cdeb1e838c3da1d01252481f7c06149b0b8e7df48c2a2ee5961f4550d7b662
-dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.gz=d51238e1ad2329b9309e94b40f3374788e2fda9bf47466841a841392835e8a5e
-dist/2025-04-02/clippy-beta-x86_64-unknown-illumos.tar.xz=6ad33945045790946fae843f63a805e60c09157e106ff342d3b99a201cd221e1
-dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=64b4f85d9eb75172928b46540090128ce9eec00e275d9027f74d0d5d4106bd76
-dist/2025-04-02/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=b090383b4ebeae96fb340f0a363ee0276eb1f17a4f2a0f2ed81aff039f21bf78
-dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8d8025922c563bb1c872111722a4de298a8f85cd5be3e4cf753d44d6b8304de6
-dist/2025-04-02/clippy-beta-x86_64-unknown-linux-musl.tar.xz=ecf15ae9eb7dafe97afd69133f13364dac09d5e6edc35ddab91fb4ac32e17d42
-dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.gz=c802af6a6f454b771046bd4a5207bdbe538cb6827becc9174dc229de5f874426
-dist/2025-04-02/clippy-beta-x86_64-unknown-netbsd.tar.xz=03d1e16eaf6f83f80e4cef8c7beebee97498135dd3138b97f97186b545edfb86
-dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.gz=c02047132bc7b48bbe930dfddb3afd31349eb042cb101a19d6e4360ea6e586ad
-dist/2025-04-02/rustfmt-nightly-aarch64-apple-darwin.tar.xz=cf825dfaeb4d97eb2819ff8e46360192f480960f6b516e328ef8a9493d413a9f
-dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=588551cbfb62eb4ed4e5755fe6eb3e1499a79e24a8a75f448b10d9a2237c63db
-dist/2025-04-02/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=df666f179fcfccb316aeb1a5eb4c17710b23198176edb34ba8b98c88cb369098
-dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=b06f4aefa01300ef1827a29c9fcd2e4da0c13f3aad92b4c929f6e8811d53ab71
-dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=059a888b8db76f5a3054a9a78a131d79c49060deaf70b2e2f03a4fcab44ab536
-dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=f0117a7be9eefe70fbd2f0d3fc05c51f3a97d069dc99500520a5d0973178fc6a
-dist/2025-04-02/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=f2fa87f1e814d0fb163146cf6a47d9375fec2c3778f76c33988acaa1665dacf7
-dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=fa53d4a6fb2ee3e1607d825afcc05063c0fa0dda1a3ede9a57e1ccc72cece8c4
-dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=3d785d982878f9bda4778cca0f9365947665849d5f7d2ee4794d8c28df3ab8c8
-dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=affb343357cd4c677cdeaf3b24698f20cfa15062cb63257aaa9bca3bd7baeeae
-dist/2025-04-02/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6eb95c2021571a0c1ad3e3edf58fa4daa7711a9085e2ab61bc75799252183358
-dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=1dffc39afb9210c77e6d45b68cb801247f00afdf33107963c82a83bd94d2225e
-dist/2025-04-02/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=2da28dd8ec76744a7629619f527196689eb35e9bc60f3a5965ed69486e44235d
-dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=5b1b39125106cdcbf12be9d5786900852f54eaa1429cabf28eeb68f96a008f90
-dist/2025-04-02/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=3f2ecb3787c82a8dae89929aca4f2f3af790f1ab3c698adf21dde21c919a4052
-dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eeb8b3f10f1cd75fac4e9e13dd1aee5941f38f1ff7fcfcaa69fcc3a42ea7c49a
-dist/2025-04-02/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=afd81cfd8d5fb37427c7eb2a1429c3b06d8daa1f42002c7230718fc56e132c47
-dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=5eb0f065a5403645ebb6c01d7f27a763f9446b8a48db5b6ff962b6f7c0f3ea3b
-dist/2025-04-02/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3576e2e8ecc563cfbc4b3f464d80f8e27f412b5eb267656dc5f0316a11a2d299
-dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=5e69db53a1161ad7616f9e50d1a7fef785840bdf0ba81757d0b6811078692921
-dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ba9d18dd2d63bad1e2863c9e14bbc4bd282d03cb806d03011d2d61ce701d934f
-dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=b112f8c2e6ec011382c02a40ca07f30e1885a1396a7f2c30f099e56d756f2f54
-dist/2025-04-02/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=42af68aa0b77306187d13ef881ee4327856f505a8a518f46244ffb17037f7e4e
-dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=ed4277c9c8a27fdb97911bb9fbb46385b5fd807ac9338d31eecc3240bb0bc5c2
-dist/2025-04-02/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=4cf3a7a64edd09b5d8ad72af545c15013842072e70789d1741f845f27c60566d
-dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=65d49556ac1abd1da9cb7c41e518f85213ee2b1f05559c917614937d4c0cada9
-dist/2025-04-02/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=535ea938d888ea12c139740e5d25ac4b82135b3274b8d86c3c59e36928922ec6
-dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=9776e0c641ae8a229453fe1fbdaaae05ea0caf37bb4893a00fe86e5d63d1241a
-dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=bf73cfd35802b2706d0db96c854e8a4c45398297a59aef92226ac28d8bb69417
-dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=307012d0741898b3a2840ba3535832943ab6127f27323e587e1918b2023b37a2
-dist/2025-04-02/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=79912529a393cb77c604f5a16d5b22611e938971656efd57fc5ef1980ffad35a
-dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=854280cb3eeac146196ba30c8f3a010d568bf5bf9613d1870bd052a2aa3a03c0
-dist/2025-04-02/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=36e6cfc2b333cf077e3e1bf651acab4e6845330fa151848926d7b33fafa016f3
-dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=19409bf4daa2e4d76c99659d7348f9a7dd4eb640c8bc81d93dc9170a1e51b7ba
-dist/2025-04-02/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=999346ff469e15507ec43c0b265a94b98ee99a0096d68ea0307a2280d138838f
-dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.gz=6a52a943d59edb9e6ed97643b01a2ca2f51abb6fba1b4c9b73f59646372aac01
-dist/2025-04-02/rustfmt-nightly-x86_64-apple-darwin.tar.xz=3701a72b39a31e31c9fe65afa660a507088dfe6039867a2019bfb69970872bad
-dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=c0dbe39a6dc72d96446312584055cfd75a4304c4859016ec7590d52813f0736c
-dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f9e8814cf2e0241bbe40bfafc62bb961d87060dd94c84fba8ea00b2992eafe2a
-dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=b9a2c923b6794b3462882a9f5b1579e2463024a72ff34cdf4bdfd8b0f51ee528
-dist/2025-04-02/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=c5e8272c451a3d685842e07a996e8bdc305ccb02a02d39f7f4cc764be4b2adce
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d47cb1e290f09795a04652f33afba39f80f3b6dcc4b570c14c75b1d945c78f0a
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=389ea9f755623dd3d887bbff71189f86d7397c82e2f8fe660c27784cf7c68a94
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=b49f6c211c51a50309ddd2bcb4c886ebeef47e5413e6399778157bc90a37ed0e
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=d53f55b6dba14bb2e2f90510c3e432781a8aad1f871d8f38795edf866ed4a4f3
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2b8d77937298b23522ab9bd2f64a829f6faf1dccb87033f6006aa8c324474b47
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=0579d2a7c17cd585c49a42efe062466db777c1e7890f21b319234ee81c86ea39
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=65bc50db8fbe283e876b9ae7d6c15ff0461c1db8b3327f2992a99d21bcc3266c
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=120505da1a8cddfb3f549438a52b2c73c76a9f1c2f25709db13d61efd214d732
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=d19004b3f6b9fa446e23f540b21a8f314d3bbcca11f753c9a6fdaf4c7ae7a2de
-dist/2025-04-02/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=e7facb66daed07789015c2d5b092afde5dbb1349d06cd0f80ae8319437587723
-dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.gz=3783e0aa4450a6bb913fc9a9799950892e65c7af9a2c895419090072999a2305
-dist/2025-04-02/rustc-nightly-aarch64-apple-darwin.tar.xz=4d3a72db4cfcd7663803f1a0b193326e37c7faecc0c97c3903a17fbc0f7c8848
-dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=c253308683fd394b1287a4eb9ca00cb8557bd7f7f91af8b087adccf9153a94eb
-dist/2025-04-02/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=63c30a1e523266dd6f8d6bb1525484f51fc6462bd7946900e0590b219f2a8b47
-dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=74d2313a732fc8401d62b9a8610bd9a25502f0372921c0e99d9d20f0cf8e3b19
-dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=a96db92f8c7cebe6e0d140a1853ecaa038e04975d62f17950e141d8ac2452536
-dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=250e2c21af9d4b284c7455668ebcc3d1e408c20cda1abf0ee69acac4c873e5ed
-dist/2025-04-02/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=931714cf51d93fee5cc9465e9a0e9d34c771fe2aaae46994f3b00da4c95a8f54
-dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=28f993889175ba3feb78b458be5282b2564a7c9b96117fed071835ff7b47f43f
-dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=8645d1a7510cc13e2cd9abeffa71cbfb5f3a99990d27da2b05c336801a51c7f0
-dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=a86525223d8c5d67b0a92382b6ebce65761cdb83629e11bf29d625d688908d38
-dist/2025-04-02/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=06a57a2c6298bb6e477d1e04922c626142bf96b2072684aecbbbf876bb4296f1
-dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=a7fb3babdc244ea1f025f3033d13088c50696db8d6db29efcc6a78474a06769e
-dist/2025-04-02/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=b130a7efa1c2bdfa5ef51237d5233ab6bd8feade7dc596d120b6501b4766a569
-dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.gz=ebb4dda0d1ced3ec5aa14b1ef38227628db92a87f45b817d4ce41ff026a687ec
-dist/2025-04-02/rustc-nightly-i686-pc-windows-gnu.tar.xz=43a69c9382b20249495824c149ffb5b5dae2ff7407c0c431859bc3e1f1ca4a7c
-dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.gz=bf3eb550e148e89e7ff17be5e72ad0462d57f3c452bfdc46b80a1812ec2fe457
-dist/2025-04-02/rustc-nightly-i686-pc-windows-msvc.tar.xz=b2dde774c1ef573c6a889c2d78bbb98f535f22be4b20896797be2f10781f0eb4
-dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.gz=96d130960b0dc1d8fa54f53d22a8fa8cf5aa35d0b213071404122e4e714feab0
-dist/2025-04-02/rustc-nightly-i686-unknown-linux-gnu.tar.xz=d743c6126151dd18624382a4228bf90af1239fc7fd97e763009b31666fb860fb
-dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=090ec673f24758b8a4d0ce7b8c58fc6015585bd8392e37760283ffbe6045298c
-dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c71ad975a15c440890a7358b5459b7ca6b9d5e1842dd353071467c2a3f841605
-dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=8806875cee039409632e8baf5433227af04bd07d015329d9512cc4f4879f687c
-dist/2025-04-02/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=cebc3a4f1eb71e86e4e63f78e1c2f86fc98f7d23db1a3cb7e4c4d385e5591d51
-dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=643dc0fe347a78a82321b5f47b41b09025856b6383ef67274ba3324879aae75e
-dist/2025-04-02/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=955018b90daf3797497dfc423aec731e8d0320b96dcf42db1705b761e1e0dd58
-dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=aed278e57ffe0eb54328a9536607bc179806e0c2de9fccb9779a4517752899e5
-dist/2025-04-02/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=0b6e0305b13d867c677243b16613f62b07352038f5e7ad7e1865cc2d00168283
-dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e10d8eee30be690aa2e6ff58ca554d47173086d5df8f0ea8581b3fd10d4cee0a
-dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=3ca3c258404dd8718321ed8a50aa6512fea9d810120db225a3fcfe56d7b83064
-dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=ddfc329b8932ad796c0eb7618632f9ae0c5ffb7a6093ea7d5cc4185fc0537f22
-dist/2025-04-02/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=b4e82b64f2e934e17fc9b270295554a8bf0bd3d38ffffc66b367aad5bee3ad6f
-dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=116d290065bd9e8ff2ca57440e94f773f68adf79aedba767159dfb92fe1a42b0
-dist/2025-04-02/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=6e1deb0c47bba4b56bbf1d04344e45f0490938455aee421629f2fcfd309eff64
-dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=445f8a0ca579153b449fa0d36460227af68399c4227be76e4cbb3d65cef9055c
-dist/2025-04-02/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=d87bcac173e9800dc1c1b28e668a1b4c3616029d0ca53adfa4ac382733610193
-dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.gz=4342b89aed19f409df56bfac3d6ac071a02cb6839a52d19fdff9d10cc1d9f540
-dist/2025-04-02/rustc-nightly-x86_64-apple-darwin.tar.xz=cb787327895f275e6f9025bb38c6337492c839310931b8c7ba39743813621701
-dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=6cddd0d3cf18780b36776fd0324643a36b3294923531a741cc763516c8238caf
-dist/2025-04-02/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=cefc15752bd84b290f50b958b96feb0134d420a10c6f36791424c762cda08abc
-dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=731e968787044081453a559a95579435654b47f91a9b7f94579ac007ed3e4cf9
-dist/2025-04-02/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=3d9b173043aed73aa3ab1fa0b14d0ce2149a4943f4bb10aa1e31af619afe0eed
-dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.gz=c0df2f0a354d2d657d8ec8091bc094060321b343c8e7bb8e4315cfe042dacfc3
-dist/2025-04-02/rustc-nightly-x86_64-unknown-freebsd.tar.xz=8933bc0361484ac7c6b226defaea73eda5c4e10462e7ea54052c7e1d370e48c0
-dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.gz=5887f913ac80dfe9826619227c66eb234a2b4848e6bc4f41c6fdd8102bf981e9
-dist/2025-04-02/rustc-nightly-x86_64-unknown-illumos.tar.xz=4a54b8b09eba43df0d99fb6e03177cf8ba2214a5810be52ac33ee3d9d33e98bc
-dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=1c0bb76acd7944804d52c3139f4dcf154d3221cdeb300bb6b9bca726cd6ad30f
-dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e67a33440c3e021ff2dd41add0fb05db6c0e8ae68bd30d33e8b3185b0bb7191b
-dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7
-dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594
-dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542
-dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843
+dist/2025-05-12/rustc-beta-aarch64-apple-darwin.tar.gz=e5ec8453efc1f51d37d5031d87d45a327647614b00993d1b7f477c7d2e6c7b16
+dist/2025-05-12/rustc-beta-aarch64-apple-darwin.tar.xz=6711902d59079cd57d6f93e951d3028acb5cef0f59a2ab87e1688edee96f6471
+dist/2025-05-12/rustc-beta-aarch64-pc-windows-msvc.tar.gz=7168682081144b8eacab42efe6c9ddb9ee6964712d271988345e63d2d6faac9c
+dist/2025-05-12/rustc-beta-aarch64-pc-windows-msvc.tar.xz=5794e0d6bed097d349e138c7602a083f4025604f711328c0a4548e27f191444b
+dist/2025-05-12/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=c4d31776d1b74dcc6184c2ed6064667b1ade59c68fb355bee812a805f61234f9
+dist/2025-05-12/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=970b0c910f8ba2b5b470ffa7959466526b0f99211578f7d8ceca8d0aaa23fe1d
+dist/2025-05-12/rustc-beta-aarch64-unknown-linux-musl.tar.gz=8e9c80f826b4571136f082d3cadbb4668167f19688a3da91fc732464b5a604b5
+dist/2025-05-12/rustc-beta-aarch64-unknown-linux-musl.tar.xz=09731185aeb15263cfed5786ccc78fee0db70f82aeb5409f8bd8b03b0566d491
+dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=4ae8dec81d8f2d1aff7710a357e3c56323cae56bacd6b014fdb4058c06bb75f0
+dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=4767de7ea81913c6ed33907d93dfb56664d9bce0d095f33f0ca5662b284a94d7
+dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=d2233f4e687bb1bd407593f6d7a8c288581b7209d758be49f0681e1f556083e4
+dist/2025-05-12/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=a8f9778a765d9fa8a0651b7d6fac8fdebcbaa61e903a32e7cbcd88bcd9418bd3
+dist/2025-05-12/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=bd2ee7918df85f24a34911b91a233663b4cf706e7c54784c78fea8e58c12ca91
+dist/2025-05-12/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=9b1a1c4eb35d3c1ec97132e33fc6551ffb280d6b2c9d049bf0392441674d338c
+dist/2025-05-12/rustc-beta-i686-pc-windows-gnu.tar.gz=729e4d7a116d8ee2a42489484429b138bafc14b43c87adfedaad442515e61c15
+dist/2025-05-12/rustc-beta-i686-pc-windows-gnu.tar.xz=8272b95f1d99dff28f22161d0181ac0e64e1909d51448f9ba4bcbe09690e79a9
+dist/2025-05-12/rustc-beta-i686-pc-windows-msvc.tar.gz=13a7327d08d26ba1911071c798d520b74422e320f5cc1c41d4e215a5615e692e
+dist/2025-05-12/rustc-beta-i686-pc-windows-msvc.tar.xz=0f9ce8fb06bb1ae460ee82601c269b885c109729df342e5b6b05b9dd9b51560a
+dist/2025-05-12/rustc-beta-i686-unknown-linux-gnu.tar.gz=82b54be8042baa56e1e6c0346f2044a84c4a50b3df6fe813d45eab21e1fe8935
+dist/2025-05-12/rustc-beta-i686-unknown-linux-gnu.tar.xz=48c9a8181b6ac7b7b6fb4535391c0498965127f5b5ac694de7eb1dba7ed8e9d5
+dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=768156149054211735ec45d0091a8e7dfac16a39c44e122af5b28b316a45fd00
+dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=50a38f72a253bfb8005a9cdd49621289f8b4a2373247957f520f5c5d1f12db29
+dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=f79bb58d8e2c80270a4c9d7076ce8645b2ea3f64db5077b085cb4cc6763f5e17
+dist/2025-05-12/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=eafeaea2813e34ef0606a9f935fe1a104417604686ef9144b899fe97de53aa67
+dist/2025-05-12/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=f557e00500071835712afdc9d91161a95b1cca5cc4e32abebcf5d35a9147eb2b
+dist/2025-05-12/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=72fc4d26e06d74349e65415da211429ec92cd479aae78f82e223f3f760b0e63a
+dist/2025-05-12/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=a67b7e5e0b30227b07a41829c5e88180d9c404c2ce37fcb10d8df702c2b3c222
+dist/2025-05-12/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=0c4cfeb6555283e58b75533930783e7cc3c838f9c8eb34938fa60656b15568a1
+dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=7e6f02eede8d87cd5bbcd8dcf8235ebabd1237fb294cf1d0dcfaf961f3628d95
+dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=a5e9612d42f999a7b0fe22b2d5d5def21162aeb604c4625fc70259c5ec2b669e
+dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=8fc92b9e35110a53458e08b49db1809a23060f8d05e742561cd746fd206085f2
+dist/2025-05-12/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=8b3fc4ac4423bc71b7402554436d1e6e62ff06b36c69f7be724e8ec5ebf96352
+dist/2025-05-12/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=d0777e5ea794a9d19a2a1744acff649a1bac8fc616f6df41410553ac0b3c275d
+dist/2025-05-12/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=849039740272c91141862a028f45889d4874ddc83842a66b906df37b7a30f9de
+dist/2025-05-12/rustc-beta-s390x-unknown-linux-gnu.tar.gz=3230ab1516a19cf803952138ef7f815ce321d7123539539249b76f6afadcf9ed
+dist/2025-05-12/rustc-beta-s390x-unknown-linux-gnu.tar.xz=12c8e476a73d71d58d5438ce94bb2fa822a8d043015b0961af14096d68c52daf
+dist/2025-05-12/rustc-beta-x86_64-apple-darwin.tar.gz=01717cd3b5141d29896caeab17ad61a27b8b7af6460745f245d67dd066a09924
+dist/2025-05-12/rustc-beta-x86_64-apple-darwin.tar.xz=fceb7e0f431f84621a22ae50ec9694cd0ecdf90801f953295b1975b0aedb4fff
+dist/2025-05-12/rustc-beta-x86_64-pc-windows-gnu.tar.gz=1f7abd7650cab64cd09848ac8de9b7e0047f6c77eb433140fbae8ae8b522c019
+dist/2025-05-12/rustc-beta-x86_64-pc-windows-gnu.tar.xz=4e3e07967e44907cb2b2ccb733b969014ee6efedb82412dc81f95533d2d473be
+dist/2025-05-12/rustc-beta-x86_64-pc-windows-msvc.tar.gz=3cc10eb4187e09a48efa5351250e09c83edda4296d605dcb886eb81f9d6580af
+dist/2025-05-12/rustc-beta-x86_64-pc-windows-msvc.tar.xz=9ce5c89a9b2e7360c7991c3f976bbbe9bf9685854d1019aa6dc1cc5b9d13eb88
+dist/2025-05-12/rustc-beta-x86_64-unknown-freebsd.tar.gz=3a9e92319e91c0498a3e54ff5ae00f4e1ecfac9b0d4f291885c9feef89d356df
+dist/2025-05-12/rustc-beta-x86_64-unknown-freebsd.tar.xz=6930ccd83b6b63d0a876eb5ac52c32a8449fd4cea8666b919494ce6358c6122c
+dist/2025-05-12/rustc-beta-x86_64-unknown-illumos.tar.gz=c1a4ad2cfa4b7c3181ea0facc3b18baea7f4138d089825915eb41630e5bac500
+dist/2025-05-12/rustc-beta-x86_64-unknown-illumos.tar.xz=44ae303a09cbc8a198c0cd947f958229b0e605842666a3b0aadb0f1f69f34ffc
+dist/2025-05-12/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=fc55fe3f5b2d206417452de880a177f59004762e58fbfa4404f0b59fdd7075dd
+dist/2025-05-12/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=a5ce304c4798bbacc998b2350d6ef79e9845a7ffb28bdf0af6066869667a0c86
+dist/2025-05-12/rustc-beta-x86_64-unknown-linux-musl.tar.gz=391cb81e61589377ab0a6780289628a805a5b1d842adc29e66ee5731f36372af
+dist/2025-05-12/rustc-beta-x86_64-unknown-linux-musl.tar.xz=7c3ac5df14b28b99e3e2d0072b5aacc59acc08621731fdebaa3199059ccbeb76
+dist/2025-05-12/rustc-beta-x86_64-unknown-netbsd.tar.gz=670beaf2ec21118fb099a1b034b33665e360b8f1920b9cbd5fb58271a8aab9ca
+dist/2025-05-12/rustc-beta-x86_64-unknown-netbsd.tar.xz=e4982c3e4b9f757485ff9aee183d973e31b2c485dbb39387c1afe4bee0fdbc30
+dist/2025-05-12/rust-std-beta-aarch64-apple-darwin.tar.gz=c2786d9e874eecea00935c62c58e2e3ddfbe11b4c99f9ce807e2251640c8f7f8
+dist/2025-05-12/rust-std-beta-aarch64-apple-darwin.tar.xz=0f2a6b28befa7d44055f32683d7b9c4de19ffd39c02fe6ce44aeffbdd1d13ea8
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios.tar.gz=3cccf751678cc229a7ca3b39cbee4467230bec235e16b48acc576c825e0be15c
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios.tar.xz=9ed9b7f1672d887fac4a0386027440651ef99c682ff21b1bd9c1ddd850934613
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=e7e6c0c7d9fa99f268d7601a127c6ce07df620fb27462dbaf933124a5786ef8a
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=abcecf3ecdb72714f35981847a91190c3f038dd5dce23a68253c7129fa6abf3b
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios-sim.tar.gz=c50ac5245e87b5e251fce3ff847ddf7d62df4490843e8a5f592515517b04d406
+dist/2025-05-12/rust-std-beta-aarch64-apple-ios-sim.tar.xz=1c913535759d008327eef49e47870d3afcf609c29aab4a188209c3cfea954682
+dist/2025-05-12/rust-std-beta-aarch64-linux-android.tar.gz=6120c1b159fa4f0279f8952aebf8cf1513f5b843905d64d1efaccaceac79c1f1
+dist/2025-05-12/rust-std-beta-aarch64-linux-android.tar.xz=57ab4652b879df33556cf04596f0f9ad9b0eee832b67e33c8c8cdf812c229a6e
+dist/2025-05-12/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=7afcbb49691f8286ac21107598a7a44363a8e385eaa648ab2e7711f87ddedfca
+dist/2025-05-12/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=ea8af597e49e924f1e04eb3435afa09720c81f43dc467461de1058265d36dd64
+dist/2025-05-12/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=2d8791f8ebff5f5f679c8b1735fdd1f0a4d7968983a5c2ddc5e036ad35b31f1e
+dist/2025-05-12/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=a7f7bb3269dd7312edea5c6fef81d373499a670804259cf7853ef346fff42ee0
+dist/2025-05-12/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=9469cb7871dc724148489180df240dd51c0388cd9bb478adf272934e38916b73
+dist/2025-05-12/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=315f3dea48c50819f925bd32a3a5181591d4370eee4def8e37448828e622ab06
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=abfaa164202c7d5d3c7e956b10a5ea612b092ee45d6c05d5c19a097617cfd703
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=71ef1275726f6c61113bf1d23099a7557461205b6be243a952fa806ef15d9413
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=d651e5e46e1251952e719237dde30ed7ecdb6b95a7cc0398fc635a76b94c552a
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=0a67ebf159539bc7f5a4e5698a0c74550da3c5e2cb0b5e1dd694ad29e1f35834
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=c0f1ecbbdd5234230d2439620c0ebe9b1c3d331388cd174cdeaf48d724172aab
+dist/2025-05-12/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=e2ba0a2853d685679422c065f266ee57f269bb5a231c5af5a791559a3609fb25
+dist/2025-05-12/rust-std-beta-aarch64-unknown-none.tar.gz=04b4eaf5910e662364b5ac3ee08ddffc2eda3957892ba99c8c945f5e1a18747a
+dist/2025-05-12/rust-std-beta-aarch64-unknown-none.tar.xz=065751b346f9c3d76e164a9edc123f277492ebfaf1d00db61027e4fb17d50f79
+dist/2025-05-12/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=056a135278dfdafb5b22c8f01bfc77b17396511d67b55c1404693d801e584262
+dist/2025-05-12/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=fc086ae7ca3a5c05790cb41dfc382fc65f929c669efd540c07131b851b78a743
+dist/2025-05-12/rust-std-beta-aarch64-unknown-uefi.tar.gz=97a6301cdd34da68d5c6b243cc125f7e34215853e405d9b34bc715aeda3223ab
+dist/2025-05-12/rust-std-beta-aarch64-unknown-uefi.tar.xz=3f2055ce638671316dc074595a35b893eea7be596cff218ec1416f3259ff86cb
+dist/2025-05-12/rust-std-beta-arm-linux-androideabi.tar.gz=299158c865df15424564be4d72921b8b25993b0671e4d462ff69f49ea29367db
+dist/2025-05-12/rust-std-beta-arm-linux-androideabi.tar.xz=6e71d518bf5f4a29b91938ee28b3c9b22509f3d97d4331ddd8ae0c1069192310
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=0a00703833d46720e470ed90f81a08d9c20f63932d852e379fe63df955e61c9b
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=57be85e4c2d4eeb4cbb19f48150693d4e6dd2969d380b1d55feb431c858e4c35
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=7b96461125b04d98a550bac5a7c3dad9c1df65ce849758d867c72ffc0b475012
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=a66602af671667fe5686c7a4e395d3dca8374ddae10cc9260e23e20f65022549
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=deaf5c7ed339c8a7bc2af94888841b647f8118854f698ece4ddbf900df921bd9
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=eac2d4d330a5300ee297c2eb61914b86efded3d494c5a73e2f91d989cb2896c4
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=479a5941193d14e2d4d50fcdbecb31103f6a143bcd3afae887d068c2ebe14163
+dist/2025-05-12/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=2483258323175c1e338be84ce52d44e15177096643beabba9d806c69cbed23dd
+dist/2025-05-12/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=528803fac28b0a0025dc50324a6980a4b561e7e3b99d7428b8ed0a73fd3dd462
+dist/2025-05-12/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=6603b9aa82cfd563d7c462ebe50058c36aff403aa9e3a1d6a305780126aee481
+dist/2025-05-12/rust-std-beta-armebv7r-none-eabi.tar.gz=6ae7f3e39e974e20e9cbfae276fd4995063c5702c41085c2b764f3c37cbbfdec
+dist/2025-05-12/rust-std-beta-armebv7r-none-eabi.tar.xz=404ae1fc0f5a6995ced2f66fa863cfff17c863096e99b5a04c841b97e6f0e28f
+dist/2025-05-12/rust-std-beta-armebv7r-none-eabihf.tar.gz=bf6aaeeba558ac148b693c4e4d231415f6e72506b50ee06b0a1f987374a08df7
+dist/2025-05-12/rust-std-beta-armebv7r-none-eabihf.tar.xz=ed3f8767f5e824c5b81178e56c6084c45c67653793128d2c08146533333cc0ba
+dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=7d2fae89c459d65fe2cd28acaa225f0ccc35b3f49c84ce6aa86e2c40dba38e03
+dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=fc05ce5ee26be4a233181b9841975c0975fc45ad5466d1001a24a01e2a31123b
+dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=0335813546a1f905e274135b2bd97c3a0c95f2e0d992d7396bc110b800d3ca8c
+dist/2025-05-12/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=7031aeca445d4f8fa351c7ad2e0e06df0386ed11f91080ea65968f1716006bd3
+dist/2025-05-12/rust-std-beta-armv7-linux-androideabi.tar.gz=9abd7fe0b7163a141d758ccdca422bd32ed4ad3618066ac022671b082f4641f9
+dist/2025-05-12/rust-std-beta-armv7-linux-androideabi.tar.xz=2bcdeb652d42755528a17b86a3b64b13b32d1ba9207cd2c9ccb43fa0d7a1c6bc
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=1bad15b2e9806e7858d5d4d58f6b2864c3f04e65d4ecb1cc448efdbf0e0030b0
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=f2d9039c903e5c309bbd17c7567462d4663665cbb7e1d98154022d98a9883719
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=13aa4a3ef68a87de259726c7c2a3906cbf013836f753b707a453bf91879f023b
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=8c4f8c044aa4ec6813cec1fed11326f67b0f2db3f20e4b441aba5656af7f0ae3
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=4c2e5ae8c903577e963af32fdbb39de6180db52907c3f508064a87a21feb9390
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=c1a12c15792f6b0de81a6e24317d7bea9af023a977ae0558ee3b4598539aa7cb
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=f789db5aebd9395daf198d5248323fee1eec27533f6d95d0f454339cbc997950
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=0376d2f2ad8f82719eabb378de3404e066da7d603e27ae4e1620509ccd6eb5b6
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=9312a8d530c6ca1e72ed35ef82700853e1fba8a1f39bcaad61277a86a974ab18
+dist/2025-05-12/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=8c7d99202e5468bbd6fcd818cb832376c00a7c4b09973e5d00b84aa4964b7ff6
+dist/2025-05-12/rust-std-beta-armv7a-none-eabi.tar.gz=c4fb94b25d21802136bc36289eea9b95e50b101f64de925a1e9d8ad8ee70aef6
+dist/2025-05-12/rust-std-beta-armv7a-none-eabi.tar.xz=6ac88ec457fd554268da3307d40664d2926174cf8e89eb173112c7248776e060
+dist/2025-05-12/rust-std-beta-armv7r-none-eabi.tar.gz=c436c2c58d224e1f9bea4703f8ab57cd3f427c60432cca50eb294dde65994002
+dist/2025-05-12/rust-std-beta-armv7r-none-eabi.tar.xz=220906e1eca686d6e4a76a80417f527d37b0659adbec940566570292496715f8
+dist/2025-05-12/rust-std-beta-armv7r-none-eabihf.tar.gz=eee1788aec77c48c76bc5ba807d42d4bbb7c8f3e9220ba1135764061a9ddf3d9
+dist/2025-05-12/rust-std-beta-armv7r-none-eabihf.tar.xz=136f3486bdd8a7e91d738a3f8c1c3b96b853aa054a76c4e83e427ea56d3eea0d
+dist/2025-05-12/rust-std-beta-i586-unknown-linux-gnu.tar.gz=72e3c031fa55d131a206d5815899a48ff7bcb19c9ac4b3dbaeab38a3cc4a3630
+dist/2025-05-12/rust-std-beta-i586-unknown-linux-gnu.tar.xz=91ca56a1e5a07e1c147a8906d366985548bd961af2aa31dfba60938e457ddece
+dist/2025-05-12/rust-std-beta-i586-unknown-linux-musl.tar.gz=839ece94670a9295148231c77573f5b2d8ec5fb9727ab6aa45b8f320201f40d5
+dist/2025-05-12/rust-std-beta-i586-unknown-linux-musl.tar.xz=27ec97a6e24184edf4a51de5500d5bb4d4833ad2b7bc771a4506589ce2190062
+dist/2025-05-12/rust-std-beta-i686-linux-android.tar.gz=d8f529a63a46bba2bd358e491d7fe0be10fee6dabf0075c40177402aeeb49721
+dist/2025-05-12/rust-std-beta-i686-linux-android.tar.xz=a061a703858aa0770d51c6c8bcdfca048efe96b561c460464b835b4ccfdca387
+dist/2025-05-12/rust-std-beta-i686-pc-windows-gnu.tar.gz=8b7eb90ad7edb050599dd477c520455ad7e02696426692a0a72094381e189285
+dist/2025-05-12/rust-std-beta-i686-pc-windows-gnu.tar.xz=f99e1d82a3cfaef05e6f088e766932a3860e7df60e1f392162746bb08eb72ddc
+dist/2025-05-12/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=5d57965f2a6ffff01619e84acdc0f7d9b2afe3c361e5094eecccfa9893eaa501
+dist/2025-05-12/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=c1b218aac6370cef9564043c98f361a2938c6ebc7784cb49b361aad3a1bfb6f1
+dist/2025-05-12/rust-std-beta-i686-pc-windows-msvc.tar.gz=fdcd4b6f391338fc0f7b72d11fc8dad9df903fb4639b893b57e729de387a9cf9
+dist/2025-05-12/rust-std-beta-i686-pc-windows-msvc.tar.xz=c8faa9123c9df0d764cac59e10e94f1562ec7bc7a792f5c63f9a9decd48a3280
+dist/2025-05-12/rust-std-beta-i686-unknown-freebsd.tar.gz=e8882425b127d01afcf6269e820bb8c4b813619b6d10f0422fea17c87d5921bf
+dist/2025-05-12/rust-std-beta-i686-unknown-freebsd.tar.xz=dabd3bb2560a7949f8984e1dcab35aa46f8e46b09e68c7f2ff32894370ed80b7
+dist/2025-05-12/rust-std-beta-i686-unknown-linux-gnu.tar.gz=dd296784ed2199b4c2d85053bce686e01cf867851b175b24781e7e8e6f6ef8bb
+dist/2025-05-12/rust-std-beta-i686-unknown-linux-gnu.tar.xz=3bb9069b4456de27cc9fba5dd2b350e5e8215f0460ce9ee375f65856958e4a82
+dist/2025-05-12/rust-std-beta-i686-unknown-linux-musl.tar.gz=008ea77ae8d982461c65c25bfcc0c41642ca51a33007a4c8d1ede8612df8f20f
+dist/2025-05-12/rust-std-beta-i686-unknown-linux-musl.tar.xz=fdfeb6df04afe1f4e414ad8292a7b75191c2507d020e69f402f97ee9ab3ccf90
+dist/2025-05-12/rust-std-beta-i686-unknown-uefi.tar.gz=dbca5a983d2eb2bd84aa7779fc54562bccf9043b31a7f52a3043f1e1e59695c8
+dist/2025-05-12/rust-std-beta-i686-unknown-uefi.tar.xz=c0d9abf38ba7b1847fc70b9dbe68f4c27d5a1adb9726dbbee77911f1d271b6aa
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=c923562d0a1d2830d41212ba140225b9c36087087dde6753e7a891383a095a10
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=5ca633c2e218939983d77cbf5738ab7d5fc4aa89093a0d1fb701ab06ed7ecf51
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=a38b4748085b3c06f2154376cdda41fcee2154f1fb409ac5137b63034cfe8cab
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=43601e0aecb02535ee46b0ddd076867248cd8654be302ae6580a81af33660faa
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-none.tar.gz=04dc49b516a638589d907f885aeafa19170683b023d0ee1bf5d78f0d91d0b94a
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-none.tar.xz=123f388b208842b3ee46a01ae8efab900c0b5b01b97eb896d26b12bb3aecdeaf
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a57452e86c5b768f1feb7f903e4ef8e76518e625c09b5f555885e1d9aaf9b76f
+dist/2025-05-12/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=e9d8b99bc4686e199f3aeda5cbfd99d49416a7ba104b494c18ae67a8d1133d9d
+dist/2025-05-12/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=3a9f4744fc128be61877967586e6c163cd6ef4e017e04578cb9101c8a9a60cdc
+dist/2025-05-12/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=0e693f7c27a34876728565152f7b6b407e1773a187742792ea2ac3f53d6c9839
+dist/2025-05-12/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=9d0f6d9cc2b7d1ceff5934a00c780337d2fa77cd9a81cbe9e041e5b18adb43ff
+dist/2025-05-12/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=afcd5c9d2e67d6c514630443d9e50d37d36722712e9275e3eaf4f460f7eb779f
+dist/2025-05-12/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=9c02e0eb75361a024d25863456c3906b845314481cd9173a6708104a21265e88
+dist/2025-05-12/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=5b0628ca22f762796c9215606314babc1237baea075c990e146ee9f9ba1ed834
+dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=9e12bd3f2b61b8753aca3a1ed117cae0b4bae2267634a6e24afc0c642d998784
+dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=70a6cf1d3e6767656657e5f76e8dd35049bd20a30517f85832c35847c9f63bf7
+dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=e2feb3c8bf2390281c71f3b76f07a5a9700e454236bdd2c8f75403cb2247b252
+dist/2025-05-12/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=0b533328ff7dfffdfb11826811fa9474c36faebe909f176d60898477d5b9d23b
+dist/2025-05-12/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=42b46c1d8ebec202131d08aa21fb6ead760a630199822b4fe88c94a5447f0491
+dist/2025-05-12/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=24bb2a24d41bfdb76dfb8817e99759dfd314ce52309d51b294db7a558114f936
+dist/2025-05-12/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=5d50c5a766344cacc6e7ebdabddfe720199fca74d1d4284a80ff5625150d7bcc
+dist/2025-05-12/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=f6f6e68c0d495b2833566deacac8a6154a220fe1f92deacd031e6b649a63a04f
+dist/2025-05-12/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=a80d128b4d0b3b5bb9316da1297b0c1cfee026eea3e9e23c546d62dda9cebd3d
+dist/2025-05-12/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=03e27d02bf685f6eb1281fc48d417dcf9f934587fbc743d6e7aac6e0c3691d5c
+dist/2025-05-12/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=67185b764c3423704af10318f44f0f310349191d62785bd8cb85ca2bac7f935a
+dist/2025-05-12/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=8ef88ac6044c84815bbbcd2b5ce4128349633addf40bb8c439b9a0a07fc5e179
+dist/2025-05-12/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=2ab3bbb6de6a5281f8aa586e5fc15d575a34b17b4f44908347d7a776c924add2
+dist/2025-05-12/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=321b0167c9481ab88ff44bf920fa15bdb4e07c864a90b6777f3c8dfd0e5c5ec6
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=bede2674247df8ff2153808f499ee1c1a7a909ff87600513ebc2998f43c7c1ea
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=b903c9ca2344fd1323695052f74b9562f6dd3cdde4872f935bcba6c0fb988dce
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=ad90fed7ed9137d04aa8c41d1c7e856dd8cc57a0f4b7836b22c9b1932a24a769
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=78372e3e32174a2cfa12dcd426e36fe29ff76779d8815944e6f6c7be4a3c55fe
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=a781d0ee95ae3012e3d016ae1b029ca8507ff549a6b1e0a6f052bca6d4afbc7b
+dist/2025-05-12/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=23b1cf7192f044a0f46ccedd654aa203dc0e9fad47c5ffc2a1e6717bf6598d69
+dist/2025-05-12/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=dfb15324b8047bd26a58a26d373af441182808203c06a3d4e595d79bca21b757
+dist/2025-05-12/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=432dfeb9231b67537dc5c77941ee26fd73404ea16dc1be4071b98c13680ddcaf
+dist/2025-05-12/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=cff18fbbbe323c67779651dd6e3b94a76a573567720985d59a091c26a3c33110
+dist/2025-05-12/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=c5f25038ba5be3ffddb6966e89017de862a0d9f267a57eeaae81b3b2a44d5690
+dist/2025-05-12/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=104d762d5a45fea227880d2395068824f9202e5a7fbd30bea478bb1ee6899ee2
+dist/2025-05-12/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=de1f15d6cfafc275108c4584a294128962dabe54bf5a1f6e81da3508ea9e8a14
+dist/2025-05-12/rust-std-beta-sparcv9-sun-solaris.tar.gz=531562c65d558a993128054fcfb29f0d408a40318ecd5623b5b24636bd7b0a07
+dist/2025-05-12/rust-std-beta-sparcv9-sun-solaris.tar.xz=af866deae0c10ce2b11c0ebe37fdafef79285bc694eaba75213316ab125b198d
+dist/2025-05-12/rust-std-beta-thumbv6m-none-eabi.tar.gz=ff623d437bda1c0b8cd8affd2a6bc165b8224a5467894aa54dee63b1b6939fc6
+dist/2025-05-12/rust-std-beta-thumbv6m-none-eabi.tar.xz=d8743e42057014ef2742cec5b93e34d5cde5a658d3ed9e7e738276387985122e
+dist/2025-05-12/rust-std-beta-thumbv7em-none-eabi.tar.gz=0b097cef25dfe72f692cd6d9dd2df85a2fc5ea9db87b8c06b8f310c239c74624
+dist/2025-05-12/rust-std-beta-thumbv7em-none-eabi.tar.xz=e7fd61ad7660c7f8c62ae6dbbd238305d997fe7539dfffb8fd0df2205656b5a9
+dist/2025-05-12/rust-std-beta-thumbv7em-none-eabihf.tar.gz=d6b3c40bd84fe352c1a88dfbc3c0f9012dcc1d82b860ce68c1d21a8d452fa662
+dist/2025-05-12/rust-std-beta-thumbv7em-none-eabihf.tar.xz=b2be1305ae382359f81e0bff16341719b6ea7731ff833205dc3fd99e7e978fb9
+dist/2025-05-12/rust-std-beta-thumbv7m-none-eabi.tar.gz=5452dc0f152065e887178423e324bf3082885b922ac57ff22c156cf7c432e184
+dist/2025-05-12/rust-std-beta-thumbv7m-none-eabi.tar.xz=5331de420a79f521351a1ea3dd501cb00b21e1979eb23dfc871ce33abca68dd7
+dist/2025-05-12/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=0b2ffb463dca747f00cf063d8fb07971df80882d3890c34ba82fbf1b77655dd0
+dist/2025-05-12/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=2f7c2bde8ae4b911889dc24a8fbe2d1539685d46c71689e5e8362cf46c391019
+dist/2025-05-12/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=1d29e86aa77e277ce1598313d6851f2f077b023217f1712d59eb76305fc773fb
+dist/2025-05-12/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=73dc975b217329d6ad44b8e8b3f72a3396597a207df7d7222d983a155ca05758
+dist/2025-05-12/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=c34c686a62afb45b9e57b3d487dcc1f66396bd7804a9c0d9696def0936a2ba1f
+dist/2025-05-12/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=1527843f87588ee28aaedbb0590bb809c24cbde6a5264151ce5fe01baf70176d
+dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=8225d6b35a55d7937bbcb7f2e74ab8ec0f23fcd69a48c59391e9016d9863151f
+dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=8c59ed4aa0a62ff8999570b60a6b9c468ea52c45642ecfdc515d6f2722fd821b
+dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=6a5804a7dc199f696867e4612d1381910ff9a13b5516b2906e651451d8ec23e8
+dist/2025-05-12/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=11205a43892169cd0aad2764f5d7604a52d13292978e7e851cef2d8e65ae6fe5
+dist/2025-05-12/rust-std-beta-wasm32-unknown-emscripten.tar.gz=962e092960bd3074dc966c1928a4adfdc16d6d811060e719dc1a84061132566c
+dist/2025-05-12/rust-std-beta-wasm32-unknown-emscripten.tar.xz=5d7fe7b3fe3b022c95d96e4027767b44a7e7980ca5c894839868919a0bb4b5bc
+dist/2025-05-12/rust-std-beta-wasm32-unknown-unknown.tar.gz=38afbfef695bad377ac9d3a4d7d9037b500795c3a75f907bf60acd4cac2b4cd4
+dist/2025-05-12/rust-std-beta-wasm32-unknown-unknown.tar.xz=f5f670d35a843cda6f5213ae02a99c3c6d1e30f3ab651be0087bf8e4de0911f2
+dist/2025-05-12/rust-std-beta-wasm32-wasip1.tar.gz=e7faeb24fac65f565e0145166d67a30b02b26f0df20791f3bdc31169846a0e2b
+dist/2025-05-12/rust-std-beta-wasm32-wasip1.tar.xz=0136f4434e8a0edbbe050899a17ae2b2825aeb4b98c4fb80f8eb25c9ea6623ab
+dist/2025-05-12/rust-std-beta-wasm32-wasip1-threads.tar.gz=2ed823ff5c3704f91048300fa31624cddeea8086cfc654fa2fea4adff58fd901
+dist/2025-05-12/rust-std-beta-wasm32-wasip1-threads.tar.xz=6f156a460db83c271b43c37709ce5724fb8059c44b29e08c2b2da27c32c06e5c
+dist/2025-05-12/rust-std-beta-wasm32-wasip2.tar.gz=ecd1ba1fec2e1e87b5f30b341e8228ca98545143adb8acd6ba53c7503f581e34
+dist/2025-05-12/rust-std-beta-wasm32-wasip2.tar.xz=593976f715c77796cecf6f7f2b79fbd4f49c10ded0349762e8312052497f1e28
+dist/2025-05-12/rust-std-beta-wasm32v1-none.tar.gz=396eb4c1e4cd930f045b092bbc8203315f494ea32c836d62e84f63ead124d886
+dist/2025-05-12/rust-std-beta-wasm32v1-none.tar.xz=9b827d1941a1d67a32a255342b476a19f57de06e53a9e6798bf00688b86eb2e0
+dist/2025-05-12/rust-std-beta-x86_64-apple-darwin.tar.gz=2796de44843d68141c6330f0e09fbabb5c3a8f34470d2948f1ed93b1b9dac088
+dist/2025-05-12/rust-std-beta-x86_64-apple-darwin.tar.xz=881e98599e5b2475e8c9f6b81e0ad6a51e8058cb2c7fc893ab57c19cdcc80804
+dist/2025-05-12/rust-std-beta-x86_64-apple-ios.tar.gz=8203faeaf21dc2c86b35d4362413c12d01de33da4524008c6261d3c87be9e51d
+dist/2025-05-12/rust-std-beta-x86_64-apple-ios.tar.xz=13a59816008d3d4b0fb20680bfe2f1c2ae8ca7eed0bdf717817e03693724eb25
+dist/2025-05-12/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=5b906fe2d801c572696cd93564723338385eb574587769f79506cb3e6c87452d
+dist/2025-05-12/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=1624a408800a895d8fe71bfc71876e52349c3508e9ddabd46d89d3274ede2dd7
+dist/2025-05-12/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=6722e76457289c6551f77fd462058862d7fb8597e1714cf66925b21e5af75c7b
+dist/2025-05-12/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=8097f509383cab4e8e444ccbf7f5d91fe35bcd2cd2017ab78bcc692c9fd1ecf4
+dist/2025-05-12/rust-std-beta-x86_64-linux-android.tar.gz=eb3124653c908003185b36aa9829ea983f4b44e11a96da69c2585664a67bfeaf
+dist/2025-05-12/rust-std-beta-x86_64-linux-android.tar.xz=4f29c6a0458ed5e37ee7a17643ff7854bd6ed029c46cdd0707019d01523a7a62
+dist/2025-05-12/rust-std-beta-x86_64-pc-solaris.tar.gz=319663b24b449df3f8063f64bd849969999a441b9376c86e6eea15cf3b872e5b
+dist/2025-05-12/rust-std-beta-x86_64-pc-solaris.tar.xz=13280470aa4c84ed6ca200664ebf3a6aa084550a82c06505b3178caefe3072ef
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=d97cf2b52f013b5cfdd9c5a3885ea70accdf52e2f957e086018d88731c8c1964
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=a2685ab1c204823b19809e47b00f2c48c5f2cc2faea05ac2df935732a7412441
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=50c0f770a938123f704837bd3313dcb12842aba75b687282a9aca6c11b11ba8e
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=8f0d04c8d55f23235f8dec94c5d5035405afd513b082f00b257bbb86cd481240
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=e633aebc178d4846a3d26f796405dde13115560c23bd2955c82afea8ab7c8d7b
+dist/2025-05-12/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=8125d5bb9a9205ffab43d0dcd56402320643101169a49098a98ee6ae785c0ed3
+dist/2025-05-12/rust-std-beta-x86_64-unknown-freebsd.tar.gz=c089415c86c9f74a454b82955911e84c9138ad66757e4da689381a1bfbd4cee5
+dist/2025-05-12/rust-std-beta-x86_64-unknown-freebsd.tar.xz=a930b94bc005ce2b09b4d67abf47bfeafad8c7ab6ca5c15acc10e023818e7b25
+dist/2025-05-12/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=f74e77eb803d1ca244e1e97272578ec008e9c373af92887318d9281204a798fa
+dist/2025-05-12/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=2fa583fcde17c1ab2f2d148af9467fa65f6bf6a0a1801e957fa15a79e6de4f78
+dist/2025-05-12/rust-std-beta-x86_64-unknown-illumos.tar.gz=20d16ce11adf468da51b30c0b55a46ce3bd030eea9f9fdb3f65f36aa442a3d71
+dist/2025-05-12/rust-std-beta-x86_64-unknown-illumos.tar.xz=dc1f2d3c1a0ae59cbfaa09b2d646645cb4fabb151edbf92975e4c8a0bfa54eba
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=05b2e5ded14501cbdc86c0510faecbf873e30d2d70724013bbb176b6f4039b44
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=a18281579cb61ea26ae0062428f7a49e51c4a928102a5eba7ff96b0ca38490c0
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=a5285ae02217d64c7bbddaa3dd1f68c361f2849479a6d75edf1d551751886f7d
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=4c41edc4f4cd1f24107b1b003a1713af3b456ff3e933781c5d4ef21a490df5e7
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=2d4c1666d456e810353f8b386d0d331812f84d9a17344953e5f4f4370bdccb0f
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=287f51dbc6e4273208869140b9c2e0de2896c0cd40f7492396ec0bbb8989a82b
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=e20af62d1900a5e10cf766ddcda9550176ab5f41111e09d57167e4e23e68d005
+dist/2025-05-12/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=7837f4880ce5d5251213d17867a6c61977504840678388fe245e0433086f409e
+dist/2025-05-12/rust-std-beta-x86_64-unknown-netbsd.tar.gz=17d2a43bc24e4e49d54315c7eb0e4952c3118b278b0a564fd588ea4ce0e8d90e
+dist/2025-05-12/rust-std-beta-x86_64-unknown-netbsd.tar.xz=ab34b5b10273c639805956665cd6543749cff2748c53980f80342facb9171b2d
+dist/2025-05-12/rust-std-beta-x86_64-unknown-none.tar.gz=d8387a8478f6a937944d684f852dee18d584344ab84425d228489dee324c318c
+dist/2025-05-12/rust-std-beta-x86_64-unknown-none.tar.xz=6ed8c2c72d547c7cc6b32a6080c346915de02a1ac02f032b6320fc7e3d45e330
+dist/2025-05-12/rust-std-beta-x86_64-unknown-redox.tar.gz=7f3a62578694121ef90fd08ab7a82a8fb27d86f164d7f73edb56a2e360198f41
+dist/2025-05-12/rust-std-beta-x86_64-unknown-redox.tar.xz=44f7ba0ca447050ad3eb7be0a0e41fee304dad2ce359c854848b7430c42b22d8
+dist/2025-05-12/rust-std-beta-x86_64-unknown-uefi.tar.gz=f78e6eca6ff517571480a6bbe20099d170f6a6b2ff0e64544c41dc77588ed890
+dist/2025-05-12/rust-std-beta-x86_64-unknown-uefi.tar.xz=d2a733aad6929be6135676307bd4576eb168e11192c24051e0be4a713b5733c5
+dist/2025-05-12/cargo-beta-aarch64-apple-darwin.tar.gz=43afffa0c5f7287e205a63871b555be144e900f8d8d67e4ed0654b50809b7338
+dist/2025-05-12/cargo-beta-aarch64-apple-darwin.tar.xz=705f051543ed8cc7011d7a866f345c3aa22c9d24f5325bffb9d9676e3c26142b
+dist/2025-05-12/cargo-beta-aarch64-pc-windows-msvc.tar.gz=c0911e84ca85de5e8c9550e2be08dd85458ba31516e282044c9149bf8bb56fa1
+dist/2025-05-12/cargo-beta-aarch64-pc-windows-msvc.tar.xz=7335470fc1338b95edc81777eb0975cd5cf5cdcdcaefc7658f356ef3e0c54fda
+dist/2025-05-12/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=99071e036041b47f78b71f1ff2ef5699b96a126ea84010ac031ee8d52d7c5873
+dist/2025-05-12/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=a9be2eeeed37905e83beb4265f4f45086675a0f5ff25db0e6bc0c5164257e1e1
+dist/2025-05-12/cargo-beta-aarch64-unknown-linux-musl.tar.gz=b38fa8d68c27b4989b1dc94caaf6bec833cc8e6d4464b859451d495b081c5b1b
+dist/2025-05-12/cargo-beta-aarch64-unknown-linux-musl.tar.xz=95a839bd2f928afafbe1058cb185b95e0099ae15d5d3030a3493724f40300ae9
+dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=34cef4599ece9c218c3841ccff9a627a69909eb733c19441c19de5b68841845b
+dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=cedfde42e95a0e86c3be841965c20f1c8bcebd20d88f38b2e694017a8afa745e
+dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=b8f1a0fca9b32362da6169b41fd58d53af6b02992ac5666cdeed03aa6150dd0c
+dist/2025-05-12/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=8f5b040e4099a03418b72b5975419089e7fa15a947b04ce6dd18f450cc21f2b4
+dist/2025-05-12/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=2f526034ad1280d152861e700fad2aef95759eaf17780a3a00d71e8fc6d8520a
+dist/2025-05-12/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=b6fdc7a08740d06e29aa678f4f9cb2dfb57fb863605fba1cce67d71ae1c1ace7
+dist/2025-05-12/cargo-beta-i686-pc-windows-gnu.tar.gz=f8b1e0227f5c1c2334cbcf53ebe5e94e01215ce21de2c5c9846e0ea7dce8e777
+dist/2025-05-12/cargo-beta-i686-pc-windows-gnu.tar.xz=149bc0d8cba9924db3b882795b6dd17f3d0a01bedfa75143dfdb7623cc7c4684
+dist/2025-05-12/cargo-beta-i686-pc-windows-msvc.tar.gz=b8462286bb1746bb789f580a14f1c5c37b108037633d9e8fbc5e2e6638e12a5c
+dist/2025-05-12/cargo-beta-i686-pc-windows-msvc.tar.xz=f07104b3439e4cfcf5c96dbf6bf4428f677f45449ce2a5595551884ab0a6870a
+dist/2025-05-12/cargo-beta-i686-unknown-linux-gnu.tar.gz=f68dece61dc087622d9e622944c4c13cdfb056eecdd93c9527c71637c73a708a
+dist/2025-05-12/cargo-beta-i686-unknown-linux-gnu.tar.xz=3272d868a2bc44b80d0ab11d133f66ed7a40b75d00fbb7a341adbee083dfd8c0
+dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=2fa7ef9b0f5247a650c1cf649e7f5514989a22b6c7927fa1df809e54466bc18f
+dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=3eddae3525cd8b446a4b31ea933cb859d335b0309900379868230d4a63979afe
+dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=88d56208387b4aa9707729f0b9337c32a0516dacc4c891b3c80140874dec6043
+dist/2025-05-12/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=8e4ceefb3d64560d989bf69f3d58cc07ab2e6a68d1f761ef92cb1826351834bb
+dist/2025-05-12/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=ed5705fb6dba34981727e4af215d8875de2c39d41b1c3e8653a93cdc06873975
+dist/2025-05-12/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=be618816cd7706709fc13ab268249a74f7b905e7ae6abe6ca1fda336dd38baa2
+dist/2025-05-12/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=8b53a21201661914e3291ebc6912083e1cd86ed5d202d6940c2be15724371bc7
+dist/2025-05-12/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=546260a68ec029f228f280fc439e93dc1f64b3e597cf615ff3915548ab67b435
+dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=343a00f2cc571ac779fd7647560b215650a01e877c9b15f95668cfc33c67ec77
+dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=efc6a23ffb467e1459f3fe5932e8303d0ee550853ad13b3ace12c9aa6514f24c
+dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=5c4e53aca46fcfb7d669b74872130fa2b8bf05b09d14bdce34f0322030450e47
+dist/2025-05-12/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=c2e33c9522924cbfde1109f87d12d27225ceb23c7ad801d3a5559a72715ca402
+dist/2025-05-12/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=91d578317c8fa147c22e81728da411fd01c1fcb0bdf2e054948537476b8371e8
+dist/2025-05-12/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=83fc425704b7673943583e38c31a944695984ffabcdaa4ab79b43aea03cef48e
+dist/2025-05-12/cargo-beta-s390x-unknown-linux-gnu.tar.gz=dac65289a906a32908ff0af9e9b829111295b49099fd5d9f90b2e454b4ecb422
+dist/2025-05-12/cargo-beta-s390x-unknown-linux-gnu.tar.xz=02a3972bfd62d4097da252fed278d741193f2c4face2e35ce8e84974e42cb1e1
+dist/2025-05-12/cargo-beta-x86_64-apple-darwin.tar.gz=148d0410ec2d3e540cfc27b6756e50d98b7ed214c2e5a702a9f2326e75ec249c
+dist/2025-05-12/cargo-beta-x86_64-apple-darwin.tar.xz=65e993adfc14eb7a9c3946a3d1ce35f5aa9767ece65cd759669bb82deda0adc8
+dist/2025-05-12/cargo-beta-x86_64-pc-windows-gnu.tar.gz=a69c23bfe9ec73737c22d0b6ce308a4f19625aab2f1846bc223ec6974cdd9163
+dist/2025-05-12/cargo-beta-x86_64-pc-windows-gnu.tar.xz=56b33a8c9e0bcbbdb2c6be13d7b84d077a896b21d800a3c6da64aa2ef64ecada
+dist/2025-05-12/cargo-beta-x86_64-pc-windows-msvc.tar.gz=cfd22dda3987642606f9e869264fa709d87b8ac5894547f809f60abce268ff76
+dist/2025-05-12/cargo-beta-x86_64-pc-windows-msvc.tar.xz=7075d67ef2dbf1e0d3889039d4db66042db538304c53cacd3e983eb9aa9d0275
+dist/2025-05-12/cargo-beta-x86_64-unknown-freebsd.tar.gz=419ce0f856113509f58f2fbccf9e5f864aa56c3c1a2c4029ecdb546464393214
+dist/2025-05-12/cargo-beta-x86_64-unknown-freebsd.tar.xz=d8f73cb808471883a5f6ee8db3dd5165fff5084ae744f4ffdca89fb545faaba8
+dist/2025-05-12/cargo-beta-x86_64-unknown-illumos.tar.gz=69e63b33c7f8d469232504c373a4e35df97016735be633a818023ea21de8f0be
+dist/2025-05-12/cargo-beta-x86_64-unknown-illumos.tar.xz=aa86cbf46dd2e35c10bb5725c627dc40ecb33329a866c2b0c5c274728f384ed3
+dist/2025-05-12/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=f77e6d762e13eb95d6369a26971e4108de448eb23690554914f650fadd2898de
+dist/2025-05-12/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=8e4b379bd88e8f18e5b6efe6058bad4ee60fb6c2e734ec165fee188f893f948d
+dist/2025-05-12/cargo-beta-x86_64-unknown-linux-musl.tar.gz=a04b711f9a07eee991b1ab13ab56e0f9e2c2ba2a16186be6c0d04529ca68af59
+dist/2025-05-12/cargo-beta-x86_64-unknown-linux-musl.tar.xz=587b214ddf5b85697b78d8baa9164a4b81604b8dccc969a03b1bf06ae7c11240
+dist/2025-05-12/cargo-beta-x86_64-unknown-netbsd.tar.gz=81a468f1db3cbdaddf6a1785297457d4780fbec472d0bdfda64fb7a398782a78
+dist/2025-05-12/cargo-beta-x86_64-unknown-netbsd.tar.xz=32212f4273171d78e10170c4a863d6f9990e29e26fdf6857dd3d134eb803161d
+dist/2025-05-12/clippy-beta-aarch64-apple-darwin.tar.gz=e5de69a84edb22eeaaeea2d94aafb07ed408508f68fc0989268e6dec8bae6a8e
+dist/2025-05-12/clippy-beta-aarch64-apple-darwin.tar.xz=03a9ebedbf11cf151d19f46b9eeb3f8ea765ac779b55356b51db21e83195c610
+dist/2025-05-12/clippy-beta-aarch64-pc-windows-msvc.tar.gz=5a9e27ab31a382ba91f9621508cf28fb4f5d0f2521452369ea2441598d34b2bf
+dist/2025-05-12/clippy-beta-aarch64-pc-windows-msvc.tar.xz=951c9f03a6fe0de1e94ab8f064cfc1b29b06606c38e891c2f9f1c550e9d94678
+dist/2025-05-12/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=1a241694ef544259a3c87bf271b1248ebb6fd32ac35b3ac16154e509b80c6e47
+dist/2025-05-12/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=679c8ed606c22490fb0a5a8503d898e61199e3cd17d9dd7a34c121781ca7306a
+dist/2025-05-12/clippy-beta-aarch64-unknown-linux-musl.tar.gz=26ba8ec943e4f8cfa27afcde06fd34dcf546c3a5c7668acf703a9b962a1977c8
+dist/2025-05-12/clippy-beta-aarch64-unknown-linux-musl.tar.xz=051112fc6bd906c62cf14d2fa9c7f1505540a6aa86ee0b1889e11b1925274c23
+dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=a44d29c794e49742417de03a955922ff3634ad45a5e6b5799c767f3feb2ae7ea
+dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=1650c464df6d87fcf3cea65722a515a1f1625d9e1ad6d27359455ecab849a592
+dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=1c4f6c22361665705334faf35a0a7c17d55fb3fbd2622721e8cd7c76418cfc41
+dist/2025-05-12/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=f75400fc72fd358be80cbedefc53a9002fe6cc22637687e941835acb8c5eced0
+dist/2025-05-12/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=f1a2db6029e9d881dbfe7c6589873b323358d8317865824705c0cd358fa3ef49
+dist/2025-05-12/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=9cc0a2212a36bfb39379008b781304da67c74ab4ce0909da18f8cad50fcbbfd0
+dist/2025-05-12/clippy-beta-i686-pc-windows-gnu.tar.gz=06051eca41cbd1b570725847b4d8b79f29bd20ac06878ef5689167626fd4b137
+dist/2025-05-12/clippy-beta-i686-pc-windows-gnu.tar.xz=857d43d424e718e04714562132802aa5fc9028945a3c40c34508abd165a909c1
+dist/2025-05-12/clippy-beta-i686-pc-windows-msvc.tar.gz=58bf660a2f3ecf4671de4624b12b5a35f1e530d3c16f47eb7e114d1deb1891ad
+dist/2025-05-12/clippy-beta-i686-pc-windows-msvc.tar.xz=5a36ec9ff4e35f1a49775e6657ea4f65543b47ebbb776fa1c60fa7898666de62
+dist/2025-05-12/clippy-beta-i686-unknown-linux-gnu.tar.gz=30df536f3cf6fbea2cf745ca8177f88831ed5b5e25d8fbdeee5f300fb35b97fe
+dist/2025-05-12/clippy-beta-i686-unknown-linux-gnu.tar.xz=a491efcade35834adcbcfa8f08004b6a181a8d8fbe36f6a1bfd8e092443a82ad
+dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=a16579fb92973f609f0eb215d81e1125ad9dfa9e22d5d869236bbe0a7bf8050c
+dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=45ff10aa52e6162b015b1a927dd23ef7404fbbec554e5a1b655c085d59a378e7
+dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=37e4ca4776fb278cac2ac05ece43ae569780503d0b122545eebc7a746dca69f3
+dist/2025-05-12/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=9c33b12b9c0a6d94b16a52066e3a1a8a2581db1c7549de002f0d6f4670021f0f
+dist/2025-05-12/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=a7939ed010f6cef23e23e17c7ad905c6c0f4e549c85a8ae38d743232fe8de321
+dist/2025-05-12/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=21046d6fe31c0930e4611a18dcd48f5cacdcf3b64b5d035b4449b8b5af417254
+dist/2025-05-12/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=a03df872f97472d9a4310c8097042ef80ca859485fdb95ed9bcd853de3cbe9ec
+dist/2025-05-12/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=925ff3b371f6c4ec871920c5e9fa5ab046f203c0af95f10f0996a750bd125582
+dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=5f159a1913f6a5d10b5d5140093c9af4277d8a632db5cc116065a08fc0ff8bb6
+dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=a2385ac96c42af4d77eb84ca70931e005aff1dc0e1ba272483ee82a837d96709
+dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=9c289ed719cd18c8e5b883aeecc03e46f35b6b90d191b4fb0d0b4b6c7fc5073c
+dist/2025-05-12/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=1a62cf477d5ad2ce4904a4438ab5756f75b894288a7449ae70c9f63d3b7badda
+dist/2025-05-12/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=c1abab08e81632db27613f3ac7036d8ffdeaf92e345b345bf2c3535f4d9c16f0
+dist/2025-05-12/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=611252f8b142af9a86e511ae783f41cc97104d2e5ec5835c7d5006421ff6207c
+dist/2025-05-12/clippy-beta-s390x-unknown-linux-gnu.tar.gz=d436be0f0f72db3c4933e8e34fcbb71e33b90ddcca58bc4b4360fe22e7a89404
+dist/2025-05-12/clippy-beta-s390x-unknown-linux-gnu.tar.xz=9f8086f13b6f53d44f03bc53fa3d750a9f4dc13b3612b10dba48958f4b61706d
+dist/2025-05-12/clippy-beta-x86_64-apple-darwin.tar.gz=1b4a51c42bcc9e3241ceaceab3fb22bbf8060e9f4c2c55357603c1bf2fbf75f2
+dist/2025-05-12/clippy-beta-x86_64-apple-darwin.tar.xz=42556126bad0e0554dc5464396383c75a1fcb76257249c62ca4e40971129c458
+dist/2025-05-12/clippy-beta-x86_64-pc-windows-gnu.tar.gz=59a2a00a0c4e05cd0900fd119f43d4354b9f6b9df9dd9a9b44a1cfee9c674eb3
+dist/2025-05-12/clippy-beta-x86_64-pc-windows-gnu.tar.xz=35290a11740a2fc0c02d534375ca4ac0392de41f281383d7396179f670ddf309
+dist/2025-05-12/clippy-beta-x86_64-pc-windows-msvc.tar.gz=db01970a436b89d5fe3cb5eb65ea075f7dfd15b649958b35ea8d88835d8fe1c3
+dist/2025-05-12/clippy-beta-x86_64-pc-windows-msvc.tar.xz=9df8c8ed117b2e975bcb0520601c9b4e19e0440b14d9e510d09c9b54b872379f
+dist/2025-05-12/clippy-beta-x86_64-unknown-freebsd.tar.gz=736361d62d33e969bda4cb98ea592ee7128e88c047f05b77cc025c982c27acb6
+dist/2025-05-12/clippy-beta-x86_64-unknown-freebsd.tar.xz=72f50e46dd2697c32b20ac2d0ae9ae2ea10485225dfd41dc9fa4e24d3b61a26e
+dist/2025-05-12/clippy-beta-x86_64-unknown-illumos.tar.gz=4c856630844d01f655dc9855efb3685c2c30fcf199edfe665d9cf4230774ae0d
+dist/2025-05-12/clippy-beta-x86_64-unknown-illumos.tar.xz=70bad50bffa518c4658e44dda7b6723558d68a545511228b97e18efc37a3ad0b
+dist/2025-05-12/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=4c1e0fc35732f19effc50e67f637c57699ed7e846e4201db3897740c1e34a43a
+dist/2025-05-12/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=fe53a5340c93485ac496453752a15222d323755cb20427b29b952b49f317a4bc
+dist/2025-05-12/clippy-beta-x86_64-unknown-linux-musl.tar.gz=c56f80644373fbe9bb87310d26876a86325fccb1756716db30a5bf70293d328c
+dist/2025-05-12/clippy-beta-x86_64-unknown-linux-musl.tar.xz=f4597f7ed6d0def07a32e952330cc964e49d42f84d65eead84192a29978c1a41
+dist/2025-05-12/clippy-beta-x86_64-unknown-netbsd.tar.gz=ecbc80189d470c1cc221360b94964fbd26d52b7583ea065cdd52795a48bf6271
+dist/2025-05-12/clippy-beta-x86_64-unknown-netbsd.tar.xz=f08204b9216fcb127934f2ceefeb7abe4338bb2ab79576a3a2e2077201f521e6
+dist/2025-05-12/rustfmt-nightly-aarch64-apple-darwin.tar.gz=269b22b568f60889c4841feff1c11d9c151d2655d134e966f7344f7affc6db57
+dist/2025-05-12/rustfmt-nightly-aarch64-apple-darwin.tar.xz=474f13aa57c73f4f9e3c63edb9a126ca845e63a376b7b8e35b5c6aa8fb0d9573
+dist/2025-05-12/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=9f24753d7abc9aa196a72ac54bb574f5eb375ecd5b2da42d0ed34bf0fb8eb947
+dist/2025-05-12/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=daae34864734810ff8ea563db7bf691f6c0fa56b9087fe285f7a3060247ef6e3
+dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=c21f59bc03b8097f066be7bd3a7d0febe873f321583a4c7a9a0cdf5448d92ced
+dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=574fce0d0ff06850db47da008fdc6c6551f2cc459f63f69dcf8edae5e5ff51eb
+dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=6379365fb729e0f5d57873ad028f0c2641d60bc19ac5c905a2d1772b6730cb93
+dist/2025-05-12/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=a274c20436d31f74b4144f165a2b383297316f1f96b0d89b2b86bbf38e57be98
+dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=03c3270a78c5d62517ec1b5c61414634ad58e5d4afb914f31bdc12ee0893ff2b
+dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=b309c052cdae48b23c2e89dcd7362af97f50181745191dee596ac176c2ade8a0
+dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=300baf318827928f0c824e20ccc8966d3fe9e5b5f62a0d1aeba5feae1d183a11
+dist/2025-05-12/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=09b764e2038499d23b28b8cbdb01c9480f2100a01d864b7f03905bc78412fa00
+dist/2025-05-12/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=47c087899d4155750e71a261a0c93c9f736530d991dfa7e34c1a7bb7f2aedd8b
+dist/2025-05-12/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=7e589aaaac2ab2c1211e5f5e1090b2ce1633f8b8682425aff01afd4dbd25e088
+dist/2025-05-12/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=0169fb75018dd644d7ed842472c04a5c82d46f3bfebe6d49931839809d1824b7
+dist/2025-05-12/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=96f3e288c8ccf073b1ea983ba382e341c8f6664135ad9aed7168bc05cf06ac4e
+dist/2025-05-12/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=29b1f7a4b1454bb1c6af1e720e05bda846725a8e866266a147335920e99e66a9
+dist/2025-05-12/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=71a2f81ff29fd7e4c8dbdb2ce85bebf5e8ea5889cbb41f98fd3c3816918a6a3d
+dist/2025-05-12/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=ae5458b4c0d58bc3e307c289aa44daf82218aaafc7911dadd4a09f4ca7cf6e12
+dist/2025-05-12/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=cf19b582a8336aa3f3959803cb24ad4499bc529bd58cd0766e668af5083de93b
+dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=474a34a9566402e313f5fcfaefe29188a6db1c0bd17caa20f186787267ac8e5d
+dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=c02f75eaa71f6c4d613a80dc7092d57cd4f6ef8a7de7511711fa818c0612da24
+dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=95b47139ab6e9c16acee5ac78744c3e9ac917a5e811f45adfec4fddd45e98cf3
+dist/2025-05-12/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=fe13340e51d7d81629e03019d375a72874b80f19420c77ea083292a22a9be589
+dist/2025-05-12/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=a95ed14a5bc2f926c2ffb5dfe49813817638154edef7f29522661c57ec2dec09
+dist/2025-05-12/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=d9060c0aa08e0ade2fb54fb5381f0f69dc94166741200b2ed35a46b5d9885036
+dist/2025-05-12/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=060213e707c6b8911517e786b21515e169e062bbbf96302e012a442d260789e1
+dist/2025-05-12/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=f1d4dd54017937490f559a472893fb8a00236b46bf0f57ef9222ec3bbd191004
+dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=38a57b7fac63608992995b3b983643ae213f6fa3d6a1021691334d84a5491542
+dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=f26658ea60a6424707a027b1e36488f99490bce045978c3919c7320638f60d68
+dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=07fbca58abf5fc57560e20fe7aede77137dd3f2f4cf2a6da11a80eaf6672bed3
+dist/2025-05-12/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=f56f7bb1091fbb1a8d1583beb586194e5dd526f7a0268b4ebe997e0ce7c9d9cb
+dist/2025-05-12/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=3ec40438a95a086a1c4c522c6ae018393469f605b03d392562fca4926bdf0631
+dist/2025-05-12/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=d7c342edbefe3fc22631961c2aca53cb808bc8f1df17673ec5cafcc56eaf0475
+dist/2025-05-12/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4c1a2aa84e8e1c67a111b9a622b2c6ed96eebcec9752ccc5e940460ce048f22e
+dist/2025-05-12/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=e26a0359223ca793d34ac9e4e5731923c4531dcdbf32aa8789bc9d1bda17013f
+dist/2025-05-12/rustfmt-nightly-x86_64-apple-darwin.tar.gz=dbf20af35cbe11baab7ead72ec254717642b01fdf30140589510413058af3e49
+dist/2025-05-12/rustfmt-nightly-x86_64-apple-darwin.tar.xz=7beb25f2df0877ee74231abe03e74a09c6e41a356d0cea27956b2091382dbf47
+dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=527d2d68bfd519d49936fd8941a04d787df1edf8c2c3ecc39103d55d1683a970
+dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=8744bef9d00d6f7397ef2b1b36971ad7af6389e93b5286ca60feb6137c4f6b10
+dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=50f8f2db4f410e60a6cd4ad03a762ea636076d85af05d511f40d2d2ea98bc833
+dist/2025-05-12/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=183f8742c505ab1d0488ca915509c1b0558166c6d19d8dc864d0a1686d66a791
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=f042a8c4ef96911b2cc6cc2228ff832229196b4ab5b1b04b05b22b5b9a90649d
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=9b93acd9cb8c8e062f3e47f5415adb8eae67479318b6201bf66119d467b81e11
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=fe9073a3bbd3b6513ba0fc38005b8ab1d44052e1bb10c1976bc98a62f8df5934
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=4c99f67e351758fe0db0bc7cdfe177018083b9ada2feeee952180b420e2c6ac9
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=c5a5702c66ae7de6b7a10d1c8c39af6c973c6eeebbc1fdba3b427c1ec9588756
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=8da51f6150fa5c53dead4c3db2c2d7493cc46b36d64b978e605a9d5755dfd779
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=3d77d2579fcb53a9bb6d942d44353f7b818b10504b64b790ecc3630d8b17a565
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=7e75748bcb8b25bebeb1b5aeb2afc2fc1c48f38ccff9c624cd002a8e051424b7
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=9c05c902b0db8fd8f8b44d83a95bc8722bb714d333d2a61a2e1ef140092b6d83
+dist/2025-05-12/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=d614cb69e1484f3653bc148280e7518640ec830ab8f02ddf512206ac265d6746
+dist/2025-05-12/rustc-nightly-aarch64-apple-darwin.tar.gz=ac2c35cd19b85e6356bcdb987031314afbb7e41f26418ddb0d943fc3482245c6
+dist/2025-05-12/rustc-nightly-aarch64-apple-darwin.tar.xz=a3c53f15d7b6f7c7e5f1e55c107663ef102cdb123394bcbe8a8c9c32a7e715f5
+dist/2025-05-12/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=29e3bae16967111ce72d00b931d32410ab526617bf1c88bbf90e4d32825ea7dd
+dist/2025-05-12/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=116103ab4251b366644239f8ef8d7129ae3d9588d768b8e66671497b1fa36c95
+dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=911acda80c362dd7690e5a4596e166b8ea49425f6dbbfd78ef697e69dc826c85
+dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=9cabea351ef05117d8cdfae0df334c98b12a99c4191d3e4f382c336c326520dc
+dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=81c9ed04939e8d363e060ef2808bee8dbd63435b111f37325bc8fd2891726560
+dist/2025-05-12/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=a44b2f887aeafd5ff57ff67d8c4eeaa94cb4edd2f7d5912618ee186a4d609c73
+dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=7a4047a85297d3012c00377241f3daa50b34ddc54d68d67787d76eb45f5db616
+dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=09acd09fbfa3c43738c43c8c423d3fce6dc4451ca4ee8650ab3392279cfc288a
+dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=88ffa28a612cfb661a731dd4feeb6d6fae88d7236469ded88ee74a06a1576a8f
+dist/2025-05-12/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=7c5747fb16062a786ffba5d00e1bc0e3c81ccf6154f09e21a6aa5b87c2fc9594
+dist/2025-05-12/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=c1bd5074d4664f0ac8019151aea13e051cf2d89b8bd8fa77b9ed3831a1b7c217
+dist/2025-05-12/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=20fa9e5531e4be0e54af97c8d033722c68d54ef984be3619ad84be6b579d0c73
+dist/2025-05-12/rustc-nightly-i686-pc-windows-gnu.tar.gz=fe7511b5bf7830efeec083d3414e389286ec117b53db0501d5c314eba24e3bdd
+dist/2025-05-12/rustc-nightly-i686-pc-windows-gnu.tar.xz=95677d845a5c7677b951300f17d810301397df022145f16674a58ebb1cd52a56
+dist/2025-05-12/rustc-nightly-i686-pc-windows-msvc.tar.gz=a8f1e4852ffab09aeab1ccc09fff930444871fd3b490e68a1f9ae504c0dce6ed
+dist/2025-05-12/rustc-nightly-i686-pc-windows-msvc.tar.xz=11fd3093a95e379d6472f063bfdccf6f3cf6c44956d68d121adcd1c927812eba
+dist/2025-05-12/rustc-nightly-i686-unknown-linux-gnu.tar.gz=d95876f9a84ebcc97033c81dd07fe8852f0f472db94c074f5029458fec512d2e
+dist/2025-05-12/rustc-nightly-i686-unknown-linux-gnu.tar.xz=766182f4d375138f4871abba6a8b50c3ca342edb7842b6d4bf7162e466cb32fe
+dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=58e41cb37fb5b974a78e7891c7aca2786bdf8153ac9cd134b713fc73771017b3
+dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=ec6990871579f86c0587a6f7262bb53dd7de3a79a39ca55b994475ad96f20f4f
+dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=39b7b026e95bdee7eba78804d2f8f3703a141ff37c24ac636deb755fc669f081
+dist/2025-05-12/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=0b066061a1a55836b3b81667c0c35d864055578370f00365db7226fc41f0f11c
+dist/2025-05-12/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=040b0718e4f460bb6136628ce24dca390608671b609d8e222e4ccbfedff43d6e
+dist/2025-05-12/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=f9206ff2fad2acaab1b3a30e1d7a634384533329f71ceed5ef2fce0bd288bd43
+dist/2025-05-12/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=9c6c12d9d5486c4d26d1f7d9a61625a20e3e7703af79195ec4cb7e7e22358f4e
+dist/2025-05-12/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=2cace3cec2973aa8f93f1d5bbe8cdcb36134fc2313b0131c51d2d4885bb18492
+dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=60adf24efc4a8207709ccb39bf45ff5fb08c4a853de816c239a2aec795c22e46
+dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=038e9220451a497885e7886a293986b37b83979a4a6f70b112d42245f9e4a924
+dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=66d700e4a734f1a1a4f2c5d9125fee2c20e400b85a4a72ec4d6963f7d438a591
+dist/2025-05-12/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=1198a73d12b6f556a5016a2181e1c95adf929f24df1be5a17b1ff8cf6635656f
+dist/2025-05-12/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=e1b12d459eeed0496a93db5ca6962bd15bd307a400e8bb870623d20479d75aa0
+dist/2025-05-12/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=2339af50b563056c4ad58cff24b1d59198e71e06c85f1860461e9384a0aeac0a
+dist/2025-05-12/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=4977999e15a893215a7f86ad55e195249f63c416b7a0bee3423950575a952d1e
+dist/2025-05-12/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=5745e2dd22c39abd35b19117b5514ba383058c057265b3003cda3da4aadfa18b
+dist/2025-05-12/rustc-nightly-x86_64-apple-darwin.tar.gz=008b5b604e3fb66026eca67f29ed65262f85a2e305286a5ad11642edc8eaee2a
+dist/2025-05-12/rustc-nightly-x86_64-apple-darwin.tar.xz=b2c071998e209e6b4989eae799938268dee9d8ada531956d41147e747128f328
+dist/2025-05-12/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=8791712c5513a077d2936dd26c7157b12fd8b4bfc93180f97273eb534461837f
+dist/2025-05-12/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=02fd232fa95660aa19665089a191fe350d0dfc44fcee4436be28fad82324fd00
+dist/2025-05-12/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=9f7d67cadca7abf25c5445a9f7c911a3e0a2db2e52c088cc6833e40b52bef0de
+dist/2025-05-12/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=ef2853ac4f2a5c6932f16768fb1df277b9edb8d91615869b8cfa574d6bda026a
+dist/2025-05-12/rustc-nightly-x86_64-unknown-freebsd.tar.gz=117efae53fc69e481498c1f268bbb12e382f479dc6859ad04fdfc4a84659d677
+dist/2025-05-12/rustc-nightly-x86_64-unknown-freebsd.tar.xz=14b67230c06ed6ec7597e31c6b7385782ab6a1f6bc723c5d2f171defa02c669d
+dist/2025-05-12/rustc-nightly-x86_64-unknown-illumos.tar.gz=881a6c5ff0222eaca1fa278fb517963b30f51714c3724956bb2d29c142af0add
+dist/2025-05-12/rustc-nightly-x86_64-unknown-illumos.tar.xz=3e708bcafdf8da1ceb92ad0e27407ea210144d91e30ba2486bd6758085153caf
+dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=b264a719d90f6842e3cbc8dc7d74ec356328f0a94cca279795ada5f4b22c54ed
+dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=fbe22ac8c9995feac7b13f92b8d4c16fc1cdfb4a15c06e127420762db0198443
+dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=48cf6d33fdba4e38dcc19710efd24eb863fe13bbca634e0ca02fc1647255bd6a
+dist/2025-05-12/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=7767dd1b6baf7065dfc74b4e9ce4c200616294ecd664243c6fe756522fb4a328
+dist/2025-05-12/rustc-nightly-x86_64-unknown-netbsd.tar.gz=bde7b39870fbce418257278ae56159af3f80f1688efd01d6d52b16127fd0b64a
+dist/2025-05-12/rustc-nightly-x86_64-unknown-netbsd.tar.xz=6018c06dda8f5a0ff5ef7754bf2e8692b2dfd48be525d896261aea27d682f4e5
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 7918c7eb59614c39f1c4e27e99d557720976bdd
+Subproject 47c911e9e6f6461f90ce19142031fe16876a3b9
diff --git a/src/tools/clippy/.github/workflows/clippy_changelog.yml b/src/tools/clippy/.github/workflows/clippy_changelog.yml
index 1e97154bf8a..4d84d6b6dae 100644
--- a/src/tools/clippy/.github/workflows/clippy_changelog.yml
+++ b/src/tools/clippy/.github/workflows/clippy_changelog.yml
@@ -15,27 +15,18 @@ jobs:
   changelog:
     runs-on: ubuntu-latest
 
-    defaults:
-      run:
-        shell: bash
-
     steps:
     # Run
     - name: Check Changelog
       if: ${{ github.event_name == 'pull_request' }}
       run: |
-        body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" | \
-          python -c "import sys, json; print(json.load(sys.stdin)['body'])")
-        output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g")
-        if [ -z "$output" ]; then
-          echo "ERROR: pull request message must contain 'changelog: ...' with your changelog. Please add it."
+        if [[ -z $(grep -oP 'changelog: *\K\S+' <<< "$PR_BODY") ]]; then
+          echo "::error::Pull request message must contain 'changelog: ...' with your changelog. Please add it."
           exit 1
-        else
-          echo "changelog: $output"
         fi
       env:
-        PYTHONIOENCODING: 'utf-8'
-        PR_NUMBER: '${{ github.event.number }}'
+        PR_BODY: ${{ github.event.pull_request.body }})
+
 
   # We need to have the "conclusion" job also on PR CI, to make it possible
   # to add PRs to a merge queue.
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 2b62c9a59aa..28147dfbea3 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,7 +6,105 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[3e3715c3...master](https://github.com/rust-lang/rust-clippy/compare/3e3715c3...master)
+[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master)
+
+## Rust 1.87
+
+Current stable, released 2025-05-15
+
+[View all 127 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-02-06T14%3A54%3A28Z..2025-03-20T20%3A07%3A53Z+base%3Amaster)
+
+### New Lints
+
+* Added [`doc_comment_double_space_linebreaks`] to `pedantic` [#12876](https://github.com/rust-lang/rust-clippy/pull/12876)
+* Added [`manual_midpoint`] to `pedantic` [#13851](https://github.com/rust-lang/rust-clippy/pull/13851)
+* Added [`io_other_error`] to `style` [#14022](https://github.com/rust-lang/rust-clippy/pull/14022)
+* Added [`owned_cow`] to `pedantic` [#13948](https://github.com/rust-lang/rust-clippy/pull/13948)
+* Added [`manual_contains`] to `perf` [#13817](https://github.com/rust-lang/rust-clippy/pull/13817)
+* Added [`unnecessary_debug_formatting`] to `pedantic` [#13893](https://github.com/rust-lang/rust-clippy/pull/13893)
+* Added [`elidable_lifetime_names`] to `pedantic` [#13960](https://github.com/rust-lang/rust-clippy/pull/13960)
+* Added [`mem_replace_option_with_some`] to `style` [#14197](https://github.com/rust-lang/rust-clippy/pull/14197)
+* Added [`unbuffered_bytes`] to `perf` [#14089](https://github.com/rust-lang/rust-clippy/pull/14089)
+* Added [`single_option_map`] to `nursery` [#14033](https://github.com/rust-lang/rust-clippy/pull/14033)
+
+### Moves and Deprecations
+
+* Moved [`comparison_chain`] to `pedantic` (from `style`)
+  [#14219](https://github.com/rust-lang/rust-clippy/pull/14219)
+* Moved [`manual_ok_or`] to `style` (from `pedantic`)
+  [#14027](https://github.com/rust-lang/rust-clippy/pull/14027)
+* Deprecated [`option_map_or_err_ok`] in favor of [`manual_ok_or`]
+  [#14027](https://github.com/rust-lang/rust-clippy/pull/14027)
+
+### Enhancements
+
+* Add `allow_expect_in_consts` and `allow_unwrap_in_consts` configuration options to [`unwrap_used`], [`expect_used`]
+  [#14200](https://github.com/rust-lang/rust-clippy/pull/14200)
+* Add `check-incompatible-msrv-in-tests` configuration option to [`incompatible_msrv`]
+  [#14279](https://github.com/rust-lang/rust-clippy/pull/14279)
+* [`len_zero`] now also triggers if deref target implements `is_empty()`
+  [#13871](https://github.com/rust-lang/rust-clippy/pull/13871)
+* [`ptr_eq`] now handles more cases, including `!=` in addition to `==`
+  [#14339](https://github.com/rust-lang/rust-clippy/pull/14339)
+* [`struct_field_names`] now also checks private fields of public structs
+  [#14076](https://github.com/rust-lang/rust-clippy/pull/14076)
+* [`needless_pass_by_value`] suggests using a reference on the innermost `Option` content
+  [#14392](https://github.com/rust-lang/rust-clippy/pull/14392)
+* [`obfuscated_if_else`] now supports `then().unwrap_or_else()` and `then_some().unwrap_or_else()`
+  [#14165](https://github.com/rust-lang/rust-clippy/pull/14165)
+* Format macros: all format-handling lints now validate `todo!` and `unimplemented!` macros
+  [#14266](https://github.com/rust-lang/rust-clippy/pull/14266)
+* [`disallowed_methods`] now supports replacements
+  [#13669](https://github.com/rust-lang/rust-clippy/pull/13669)
+* Added MSRV checks for several lints:
+  * [`question_mark`] [#14436](https://github.com/rust-lang/rust-clippy/pull/14436)
+  * [`repeat_vec_with_capacity`] [#14126](https://github.com/rust-lang/rust-clippy/pull/14126)
+  * [`manual_flatten`] [#14086](https://github.com/rust-lang/rust-clippy/pull/14086)
+  * [`lines_filter_map_ok`] [#14130](https://github.com/rust-lang/rust-clippy/pull/14130)
+
+### False Positive Fixes
+
+* [`missing_const_for_fn`] no longer triggers on unstable const traits [#14294](https://github.com/rust-lang/rust-clippy/pull/14294)
+* [`unnecessary_to_owned`] now avoids suggesting to call `iter()` on a temporary object [#14243](https://github.com/rust-lang/rust-clippy/pull/14243)
+* [`unnecessary_debug_formatting`] no longer triggers in tests [#14347](https://github.com/rust-lang/rust-clippy/pull/14347)
+* [`option_if_let_else`] now handles cases when value is partially moved [#14209](https://github.com/rust-lang/rust-clippy/pull/14209)
+* [`blocks_in_conditions`] no longer triggers when the condition contains a `return` [#14338](https://github.com/rust-lang/rust-clippy/pull/14338)
+* [`undocumented_unsafe_blocks`] no longer triggers on trait/impl items [#13888](https://github.com/rust-lang/rust-clippy/pull/13888)
+* [`manual_slice_fill`] no longer triggers due to missing index checks [#14193](https://github.com/rust-lang/rust-clippy/pull/14193)
+* [`useless_asref`] no longer suggests using `.clone()` if the target type doesn't implement `Clone` [#14174](https://github.com/rust-lang/rust-clippy/pull/14174)
+* [`unnecessary_safety_comment`] no longer triggers on desugared assign [#14371](https://github.com/rust-lang/rust-clippy/pull/14371)
+* [`unnecessary_map_or`] no longer consumes the comparison value if it does not implement `Copy` [#14207](https://github.com/rust-lang/rust-clippy/pull/14207)
+* [`let_and_return`] no longer triggers involving short-lived block temporary variables [#14180](https://github.com/rust-lang/rust-clippy/pull/14180)
+* [`manual_async_fn`] no longer emits suggestions inside macros [#14142](https://github.com/rust-lang/rust-clippy/pull/14142)
+* [`use_self`] skips analysis inside macro expansions of a `impl Self` block [#13128](https://github.com/rust-lang/rust-clippy/pull/13128)
+* [`double_ended_iterator_last`] no longer triggers on non-reference immutable receiver [#14140](https://github.com/rust-lang/rust-clippy/pull/14140)
+
+### ICE Fixes
+
+* [`macro_use_imports`] Fix ICE when checking attributes
+  [#14317](https://github.com/rust-lang/rust-clippy/pull/14317)
+* [`doc_nested_refdefs`] Fix ICE by avoiding invalid ranges
+  [#14308](https://github.com/rust-lang/rust-clippy/pull/14308)
+* [`just_underscores_and_digits`] Fix ICE in error recovery scenario
+  [#14168](https://github.com/rust-lang/rust-clippy/pull/14168)
+* [`declare_interior_mutable_const`], [`borrow_interior_mutable_const`] Fix ICE by properly resolving `<T as Trait>::AssocT` projections
+  [#14125](https://github.com/rust-lang/rust-clippy/pull/14125)
+
+### Documentation Improvements
+
+* [`struct_excessive_bools`] Documentation improved with rationale
+  [#14351](https://github.com/rust-lang/rust-clippy/pull/14351)
+
+### Others
+
+* Use edition=2021 in `rustc_tools_util`
+  [#14211](https://github.com/rust-lang/rust-clippy/pull/14211)
+* Fix rustc_tools_util's `version.host_compiler` release channel, expose the rustc version, and add tests
+  [#14123](https://github.com/rust-lang/rust-clippy/pull/14123)
+* Make UI test annotations mandatory
+  [#11421](https://github.com/rust-lang/rust-clippy/pull/11421)
+  [#14388](https://github.com/rust-lang/rust-clippy/pull/14388)
+  [#14393](https://github.com/rust-lang/rust-clippy/pull/14393)
 
 ## Rust 1.86
 
@@ -5583,6 +5681,7 @@ Released 2018-09-13
 [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
 [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
 [`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied
+[`cloned_ref_to_slice_refs`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_ref_to_slice_refs
 [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
@@ -5594,6 +5693,7 @@ Released 2018-09-13
 [`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
+[`confusing_method_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#confusing_method_to_numeric_cast
 [`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
 [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
@@ -6383,6 +6483,7 @@ Released 2018-09-13
 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
 [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero
 [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests
+[`allow-exact-repetitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-exact-repetitions
 [`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts
 [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests
 [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests
@@ -6435,6 +6536,7 @@ Released 2018-09-13
 [`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length
 [`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds
 [`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
+[`missing-docs-allow-unused`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-allow-unused
 [`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items
 [`module-item-order-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-item-order-groupings
 [`module-items-ordered-within-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-items-ordered-within-groupings
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 3b33f719063..45ba2f078be 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -77,7 +77,7 @@ debugging to find the actual problem behind the issue.
 
 [`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
 lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
-an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
+an AST expression).
 
 [`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
 [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 1cfc1c196c0..c7c06afb612 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy"
 # begin autogenerated version
-version = "0.1.88"
+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"
@@ -28,7 +28,7 @@ clippy_lints = { path = "clippy_lints" }
 clippy_utils = { path = "clippy_utils" }
 rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 clippy_lints_internal = { path = "clippy_lints_internal", optional = true }
-tempfile = { version = "3.3", optional = true }
+tempfile = { version = "3.20", optional = true }
 termize = "0.1"
 color-print = "0.3.4"
 anstream = "0.6.18"
@@ -47,7 +47,6 @@ pulldown-cmark = { version = "0.11", default-features = false, features = ["html
 askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
 
 # UI test dependencies
-clippy_utils = { path = "clippy_utils" }
 if_chain = "1.0"
 quote = "1.0.25"
 syn = { version = "2.0", features = ["full"] }
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index e5e82ede4fd..2b89e94cf8f 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -416,7 +416,7 @@ In our example, `is_foo_fn` looks like:
 
 fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
     match fn_kind {
-        FnKind::Fn(_, ident, ..) => {
+        FnKind::Fn(_, _, Fn { ident, .. }) => {
             // check if `fn` name is `foo`
             ident.name.as_str() == "foo"
         }
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index 4219724ed5d..cdbbe76bdb0 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -145,42 +145,32 @@ unclear to you.
 If you are hacking on Clippy and want to install it from source, do the
 following:
 
-First, take note of the toolchain
-[override](https://rust-lang.github.io/rustup/overrides.html) in
-`/rust-toolchain.toml`. We will use this override to install Clippy into the right
-toolchain.
-
-> Tip: You can view the active toolchain for the current directory with `rustup
-> show active-toolchain`.
-
 From the Clippy project root, run the following command to build the Clippy
-binaries and copy them into the toolchain directory. This will override the
-currently installed Clippy component.
+binaries and copy them into the toolchain directory. This will create a new
+toolchain called `clippy` by default, see `cargo dev setup toolchain --help`
+for other options.
 
 ```terminal
-cargo build --release --bin cargo-clippy --bin clippy-driver -Zunstable-options --out-dir "$(rustc --print=sysroot)/bin"
+cargo dev setup toolcahin
 ```
 
-Now you may run `cargo clippy` in any project, using the toolchain where you
-just installed Clippy.
+Now you may run `cargo +clippy clippy` in any project using the new toolchain.
 
 ```terminal
 cd my-project
-cargo +nightly-2021-07-01 clippy
+cargo +clippy clippy
 ```
 
 ...or `clippy-driver`
 
 ```terminal
-clippy-driver +nightly-2021-07-01 <filename>
+clippy-driver +clippy <filename>
 ```
 
-If you need to restore the default Clippy installation, run the following (from
-the Clippy project root).
+If you no longer need the toolchain it can be uninstalled using `rustup`:
 
 ```terminal
-rustup component remove clippy
-rustup component add clippy
+rustup toolchain uninstall clippy
 ```
 
 > **DO NOT** install using `cargo install --path . --force` since this will
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index 2e39f279eae..e23b32039c9 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -86,7 +86,7 @@ arguments have to be checked separately.
 
 ```rust
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{paths, match_def_path};
+use clippy_utils::paths;
 use rustc_span::symbol::sym;
 use rustc_hir::LangItem;
 
@@ -108,7 +108,7 @@ impl LateLintPass<'_> for MyStructLint {
 
         // 3. Using the type path
         // This method should be avoided if possible
-        if match_def_path(cx, def_id, &paths::RESULT) {
+        if paths::RESULT.matches_ty(cx, ty) {
             // The type is a `core::result::Result`
         }
     }
diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
index 2b2c096b049..eede6b78d92 100644
--- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
+++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
@@ -51,7 +51,9 @@ Once you've got the correct commit range, run
 util/fetch_prs_between.sh commit1 commit2 > changes.txt
 ```
 
-and open that file in your editor of choice.
+where `commit2` is the commit hash from the previous command and `commit1`
+is the commit hash from the current CHANGELOG file.
+Open `changes.txt` file in your editor of choice.
 
 When updating the changelog it's also a good idea to make sure that `commit1` is
 already correct in the current changelog.
@@ -60,8 +62,8 @@ already correct in the current changelog.
 
 The above script should have dumped all the relevant PRs to the file you
 specified. It should have filtered out most of the irrelevant PRs already, but
-it's a good idea to do a manual cleanup pass where you look for more irrelevant
-PRs. If you're not sure about some PRs, just leave them in for the review and
+it's a good idea to do a manual cleanup pass and choose valuable PRs.
+If you're not sure about some PRs, just leave them in for the review and
 ask for feedback.
 
 With the PRs filtered, you can start to take each PR and move the `changelog: `
@@ -74,10 +76,9 @@ The order should roughly be:
 2. Moves or deprecations of lints
 3. Changes that expand what code existing lints cover
 4. False positive fixes
-5. Suggestion fixes/improvements
-6. ICE fixes
-7. Documentation improvements
-8. Others
+5. ICE fixes
+6. Documentation improvements
+7. Others
 
 As section headers, we use:
 
@@ -91,7 +92,6 @@ As section headers, we use:
 
 ### Enhancements
 ### False Positive Fixes
-### Suggestion Fixes/Improvements
 ### ICE Fixes
 ### Documentation Improvements
 ### Others
@@ -112,7 +112,16 @@ that label in the changelog. If you can, remove the `beta-accepted` labels
 ### 4. Update `clippy::version` attributes
 
 Next, make sure to check that the `#[clippy::version]` attributes for the added
-lints contain the correct version.
+lints contain the correct version. 
+In order to find lints that need a version update, go through the lints in the 
+"New Lints" section and run the following command for each lint name:
+
+```
+grep -rB1 "pub $LINT_NAME" .
+```
+
+The version shown should match the version of the release the changelog is 
+written for. If not, update the version to the changelog version.
 
 [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
 [forge]: https://forge.rust-lang.org/
diff --git a/src/tools/clippy/book/src/development/trait_checking.md b/src/tools/clippy/book/src/development/trait_checking.md
index b7d229ccc19..cc4eb966f59 100644
--- a/src/tools/clippy/book/src/development/trait_checking.md
+++ b/src/tools/clippy/book/src/development/trait_checking.md
@@ -73,22 +73,24 @@ impl LateLintPass<'_> for CheckDropTraitLint {
 ## Using Type Path
 
 If neither diagnostic item nor a language item is available, we can use
-[`clippy_utils::paths`][paths] with the `match_trait_method` to determine trait
-implementation.
+[`clippy_utils::paths`][paths] to determine get a trait's `DefId`.
 
 > **Note**: This approach should be avoided if possible, the best thing to do would be to make a PR to [`rust-lang/rust`][rust] adding a diagnostic item.
 
-Below, we check if the given `expr` implements the `Iterator`'s trait method `cloned` :
+Below, we check if the given `expr` implements [`core::iter::Step`](https://doc.rust-lang.org/std/iter/trait.Step.html):
 
 ```rust
-use clippy_utils::{match_trait_method, paths};
+use clippy_utils::{implements_trait, paths};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 
-impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
+impl LateLintPass<'_> for CheckIterStep {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if match_trait_method(cx, expr, &paths::CORE_ITER_CLONED) {
-            println!("`expr` implements `CORE_ITER_CLONED` trait!");
+        let ty = cx.typeck_results().expr_ty(expr);
+        if let Some(trait_def_id) = paths::ITER_STEP.first(cx)
+            && implements_trait(cx, ty, trait_def_id, &[])
+        {
+            println!("`expr` implements the `core::iter::Step` trait!");
         }
     }
 }
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 2314d1beac7..0db4182dbcd 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -71,6 +71,16 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
 * [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
 
 
+## `allow-exact-repetitions`
+Whether an item should be allowed to have the same name as its containing module
+
+**Default Value:** `true`
+
+---
+**Affected lints:**
+* [`module_name_repetitions`](https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions)
+
+
 ## `allow-expect-in-consts`
 Whether `expect` should be allowed in code always evaluated at compile time
 
@@ -734,6 +744,16 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
 * [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars)
 
 
+## `missing-docs-allow-unused`
+Whether to allow fields starting with an underscore to skip documentation requirements
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
+
+
 ## `missing-docs-in-crate-items`
 Whether to **only** check for missing documentation in items visible within the current
 crate. For example, `pub(crate)` items.
@@ -839,6 +859,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push)
 * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
 * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
+* [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some)
 * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)
 * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
 * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 0a7724bbe4e..77573105d86 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -7,14 +7,11 @@ lint-commented-code = true
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
-allow-invalid = true
 
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::span_lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
-allow-invalid = true
 
 [[disallowed-methods]]
 path = "rustc_middle::ty::context::TyCtxt::node_span_lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
-allow-invalid = true
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 93fd2e35d1b..1134b0e97af 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_config"
 # begin autogenerated version
-version = "0.1.88"
+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 511cb84527d..ad0aea39d41 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -360,6 +360,9 @@ define_Conf! {
     /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
     #[lints(dbg_macro)]
     allow_dbg_in_tests: bool = false,
+    /// Whether an item should be allowed to have the same name as its containing module
+    #[lints(module_name_repetitions)]
+    allow_exact_repetitions: bool = true,
     /// Whether `expect` should be allowed in code always evaluated at compile time
     #[lints(expect_used)]
     allow_expect_in_consts: bool = true,
@@ -675,6 +678,9 @@ define_Conf! {
     /// Minimum chars an ident can have, anything below or equal to this will be linted.
     #[lints(min_ident_chars)]
     min_ident_chars_threshold: u64 = 1,
+    /// Whether to allow fields starting with an underscore to skip documentation requirements
+    #[lints(missing_docs_in_private_items)]
+    missing_docs_allow_unused: bool = false,
     /// Whether to **only** check for missing documentation in items visible within the current
     /// crate. For example, `pub(crate)` items.
     #[lints(missing_docs_in_private_items)]
@@ -756,6 +762,7 @@ define_Conf! {
         same_item_push,
         seek_from_current,
         seek_rewind,
+        to_digit_is_some,
         transmute_ptr_to_ref,
         tuple_array_conversions,
         type_repetition_in_bounds,
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
index c227b8900b7..67904b4fcdc 100644
--- a/src/tools/clippy/clippy_config/src/lib.rs
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, array_windows, let_chains)]
+#![feature(rustc_private)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
@@ -12,6 +12,7 @@
     rustc::diagnostic_outside_of_impl,
     rustc::untranslatable_diagnostic
 )]
+#![deny(clippy::derive_deserialize_allowing_unknown)]
 
 extern crate rustc_data_structures;
 extern crate rustc_errors;
diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs
index 5949eaca7bc..f64eefa0c23 100644
--- a/src/tools/clippy/clippy_config/src/types.rs
+++ b/src/tools/clippy/clippy_config/src/types.rs
@@ -1,16 +1,18 @@
+use clippy_utils::paths::{PathNS, find_crates, lookup_path};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::PrimTy;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use serde::de::{self, Deserializer, Visitor};
 use serde::{Deserialize, Serialize, ser};
 use std::collections::HashMap;
 use std::fmt;
 
 #[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
 pub struct Rename {
     pub path: String,
     pub rename: String,
@@ -58,7 +60,7 @@ impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<R
 // `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just
 // above. `DisallowedPathEnum` is not meant to be used outside of this file.
 #[derive(Debug, Deserialize, Serialize)]
-#[serde(untagged)]
+#[serde(untagged, deny_unknown_fields)]
 enum DisallowedPathEnum {
     Simple(String),
     WithReason {
@@ -133,6 +135,7 @@ impl DisallowedPathEnum {
 pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
     tcx: TyCtxt<'_>,
     disallowed_paths: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
+    ns: PathNS,
     def_kind_predicate: impl Fn(DefKind) -> bool,
     predicate_description: &str,
     allow_prim_tys: bool,
@@ -145,57 +148,47 @@ pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
         FxHashMap::default();
     for disallowed_path in disallowed_paths {
         let path = disallowed_path.path();
-        let mut resolutions = clippy_utils::def_path_res(tcx, &path.split("::").collect::<Vec<_>>());
-
-        let mut found_def_id = None;
-        let mut found_prim_ty = false;
-        resolutions.retain(|res| match res {
-            Res::Def(def_kind, def_id) => {
-                found_def_id = Some(*def_id);
-                def_kind_predicate(*def_kind)
-            },
-            Res::PrimTy(_) => {
-                found_prim_ty = true;
-                allow_prim_tys
-            },
-            _ => false,
-        });
-
-        if resolutions.is_empty() {
-            let span = disallowed_path.span();
-
-            if let Some(def_id) = found_def_id {
-                tcx.sess.dcx().span_warn(
-                    span,
-                    format!(
-                        "expected a {predicate_description}, found {} {}",
-                        tcx.def_descr_article(def_id),
-                        tcx.def_descr(def_id)
-                    ),
-                );
+        let sym_path: Vec<Symbol> = path.split("::").map(Symbol::intern).collect();
+        let mut resolutions = lookup_path(tcx, ns, &sym_path);
+        resolutions.retain(|&def_id| def_kind_predicate(tcx.def_kind(def_id)));
+
+        let (prim_ty, found_prim_ty) = if let &[name] = sym_path.as_slice()
+            && let Some(prim) = PrimTy::from_name(name)
+        {
+            (allow_prim_tys.then_some(prim), true)
+        } else {
+            (None, false)
+        };
+
+        if resolutions.is_empty()
+            && prim_ty.is_none()
+            && !disallowed_path.allow_invalid
+            // Don't warn about unloaded crates:
+            // https://github.com/rust-lang/rust-clippy/pull/14397#issuecomment-2848328221
+            && (sym_path.len() < 2 || !find_crates(tcx, sym_path[0]).is_empty())
+        {
+            // Relookup the path in an arbitrary namespace to get a good `expected, found` message
+            let found_def_ids = lookup_path(tcx, PathNS::Arbitrary, &sym_path);
+            let message = if let Some(&def_id) = found_def_ids.first() {
+                let (article, description) = tcx.article_and_description(def_id);
+                format!("expected a {predicate_description}, found {article} {description}")
             } else if found_prim_ty {
-                tcx.sess.dcx().span_warn(
-                    span,
-                    format!("expected a {predicate_description}, found a primitive type",),
-                );
-            } else if !disallowed_path.allow_invalid {
-                tcx.sess.dcx().span_warn(
-                    span,
-                    format!("`{path}` does not refer to an existing {predicate_description}"),
-                );
-            }
+                format!("expected a {predicate_description}, found a primitive type")
+            } else {
+                format!("`{path}` does not refer to a reachable {predicate_description}")
+            };
+            tcx.sess
+                .dcx()
+                .struct_span_warn(disallowed_path.span(), message)
+                .with_help("add `allow-invalid = true` to the entry to suppress this warning")
+                .emit();
         }
 
-        for res in resolutions {
-            match res {
-                Res::Def(_, def_id) => {
-                    def_ids.insert(def_id, (path, disallowed_path));
-                },
-                Res::PrimTy(ty) => {
-                    prim_tys.insert(ty, (path, disallowed_path));
-                },
-                _ => unreachable!(),
-            }
+        for def_id in resolutions {
+            def_ids.insert(def_id, (path, disallowed_path));
+        }
+        if let Some(ty) = prim_ty {
+            prim_tys.insert(ty, (path, disallowed_path));
         }
     }
 
diff --git a/src/tools/clippy/clippy_dev/src/deprecate_lint.rs b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
new file mode 100644
index 00000000000..bf0e7771046
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
@@ -0,0 +1,174 @@
+use crate::update_lints::{
+    DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints,
+};
+use crate::utils::{UpdateMode, Version};
+use std::ffi::OsStr;
+use std::path::{Path, PathBuf};
+use std::{fs, io};
+
+/// Runs the `deprecate` command
+///
+/// This does the following:
+/// * Adds an entry to `deprecated_lints.rs`.
+/// * Removes the lint declaration (and the entire file if applicable)
+///
+/// # Panics
+///
+/// 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..];
+
+    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 {
+        eprintln!("error: failed to find lint `{name}`");
+        return;
+    };
+
+    let mod_path = {
+        let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
+        if mod_path.is_dir() {
+            mod_path = mod_path.join("mod");
+        }
+
+        mod_path.set_extension("rs");
+        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(),
+        });
+
+        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");
+    } else {
+        eprintln!("error: lint not found");
+    }
+}
+
+fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> {
+    fn remove_lint(name: &str, lints: &mut Vec<Lint>) {
+        lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos));
+    }
+
+    fn remove_test_assets(name: &str) {
+        let test_file_stem = format!("tests/ui/{name}");
+        let path = Path::new(&test_file_stem);
+
+        // Some lints have their own directories, delete them
+        if path.is_dir() {
+            let _ = fs::remove_dir_all(path);
+            return;
+        }
+
+        // Remove all related test files
+        let _ = fs::remove_file(path.with_extension("rs"));
+        let _ = fs::remove_file(path.with_extension("stderr"));
+        let _ = fs::remove_file(path.with_extension("fixed"));
+    }
+
+    fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
+        let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| {
+            content
+                .find("declare_lint_pass!")
+                .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`"))
+        });
+        let mut impl_lint_pass_end = content[impl_lint_pass_start..]
+            .find(']')
+            .expect("failed to find `impl_lint_pass` terminator");
+
+        impl_lint_pass_end += impl_lint_pass_start;
+        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) {
+            let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len());
+            for c in content[lint_name_end..impl_lint_pass_end].chars() {
+                // Remove trailing whitespace
+                if c == ',' || c.is_whitespace() {
+                    lint_name_end += 1;
+                } else {
+                    break;
+                }
+            }
+
+            content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, "");
+        }
+    }
+
+    if path.exists()
+        && let Some(lint) = lints.iter().find(|l| l.name == name)
+    {
+        if lint.module == name {
+            // The lint name is the same as the file, we can just delete the entire file
+            fs::remove_file(path)?;
+        } else {
+            // We can't delete the entire file, just remove the declaration
+
+            if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
+                // Remove clippy_lints/src/some_mod/some_lint.rs
+                let mut lint_mod_path = path.to_path_buf();
+                lint_mod_path.set_file_name(name);
+                lint_mod_path.set_extension("rs");
+
+                let _ = fs::remove_file(lint_mod_path);
+            }
+
+            let mut content =
+                fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
+
+            eprintln!(
+                "warn: you will have to manually remove any code related to `{name}` from `{}`",
+                path.display()
+            );
+
+            assert!(
+                content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
+                "error: `{}` does not contain lint `{}`'s declaration",
+                path.display(),
+                lint.name
+            );
+
+            // Remove lint declaration (declare_clippy_lint!)
+            content.replace_range(lint.declaration_range.clone(), "");
+
+            // Remove the module declaration (mod xyz;)
+            let mod_decl = format!("\nmod {name};");
+            content = content.replacen(&mod_decl, "", 1);
+
+            remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
+            fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
+        }
+
+        remove_test_assets(name);
+        remove_lint(name, lints);
+        return Ok(true);
+    }
+
+    Ok(false)
+}
diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs
index 05fa24d8d4e..7e9d92458d0 100644
--- a/src/tools/clippy/clippy_dev/src/dogfood.rs
+++ b/src/tools/clippy/clippy_dev/src/dogfood.rs
@@ -1,4 +1,4 @@
-use crate::utils::{clippy_project_root, exit_if_err};
+use crate::utils::exit_if_err;
 use std::process::Command;
 
 /// # Panics
@@ -8,8 +8,7 @@ use std::process::Command;
 pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) {
     let mut cmd = Command::new("cargo");
 
-    cmd.current_dir(clippy_project_root())
-        .args(["test", "--test", "dogfood"])
+    cmd.args(["test", "--test", "dogfood"])
         .args(["--features", "internal"])
         .args(["--", "dogfood_clippy", "--nocapture"]);
 
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index bdddf46a2cb..b4c13213f55 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,4 +1,3 @@
-use crate::utils::clippy_project_root;
 use itertools::Itertools;
 use rustc_lexer::{TokenKind, tokenize};
 use shell_escape::escape;
@@ -104,15 +103,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
         Field,
     }
 
-    let path: PathBuf = [
-        clippy_project_root().as_path(),
-        "clippy_config".as_ref(),
-        "src".as_ref(),
-        "conf.rs".as_ref(),
-    ]
-    .into_iter()
-    .collect();
-    let text = fs::read_to_string(&path)?;
+    let path = "clippy_config/src/conf.rs";
+    let text = fs::read_to_string(path)?;
 
     let (pre, conf) = text
         .split_once("define_Conf! {\n")
@@ -203,7 +195,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
             | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {},
             _ => {
                 return Err(Error::Parse(
-                    path,
+                    PathBuf::from(path),
                     offset_to_line(&text, conf_offset + i),
                     format!("unexpected token `{}`", &conf[i..i + t.len as usize]),
                 ));
@@ -213,7 +205,7 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
 
     if !matches!(state, State::Field) {
         return Err(Error::Parse(
-            path,
+            PathBuf::from(path),
             offset_to_line(&text, conf_offset + conf.len()),
             "incomplete field".into(),
         ));
@@ -260,18 +252,16 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
         if check {
             return Err(Error::CheckFailed);
         }
-        fs::write(&path, new_text.as_bytes())?;
+        fs::write(path, new_text.as_bytes())?;
     }
     Ok(())
 }
 
 fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
-    let project_root = clippy_project_root();
-
     // 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(project_root.join("Cargo.toml"))
+    if fs::read_to_string("Cargo.toml")
         .expect("Failed to read clippy Cargo.toml")
         .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
     {
@@ -280,12 +270,12 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
 
     check_for_rustfmt(context)?;
 
-    cargo_fmt(context, project_root.as_path())?;
-    cargo_fmt(context, &project_root.join("clippy_dev"))?;
-    cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
-    cargo_fmt(context, &project_root.join("lintcheck"))?;
+    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(project_root.join("tests"))
+    let chunks = WalkDir::new("tests")
         .into_iter()
         .filter_map(|entry| {
             let entry = entry.expect("failed to find tests");
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index c1ffaf269c6..e237a05b253 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,5 +1,4 @@
-#![feature(let_chains)]
-#![feature(rustc_private)]
+#![feature(rustc_private, if_let_guard, let_chains)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
@@ -15,11 +14,13 @@ extern crate rustc_driver;
 extern crate rustc_lexer;
 extern crate rustc_literal_escaper;
 
+pub mod deprecate_lint;
 pub mod dogfood;
 pub mod fmt;
 pub mod lint;
 pub mod new_lint;
 pub mod release;
+pub mod rename_lint;
 pub mod serve;
 pub mod setup;
 pub mod sync;
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 83f8e66b334..5dce0be742b 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -3,11 +3,18 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use clap::{Args, Parser, Subcommand};
-use clippy_dev::{dogfood, fmt, lint, new_lint, release, serve, setup, sync, update_lints, utils};
+use clippy_dev::{
+    deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils,
+};
 use std::convert::Infallible;
+use std::env;
 
 fn main() {
     let dev = Dev::parse();
+    let clippy = utils::ClippyInfo::search_for_manifest();
+    if let Err(e) = env::set_current_dir(&clippy.path) {
+        panic!("error setting current directory to `{}`: {e}", clippy.path.display());
+    }
 
     match dev.command {
         DevCommand::Bless => {
@@ -20,22 +27,14 @@ fn main() {
             allow_no_vcs,
         } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
         DevCommand::Fmt { check, verbose } => fmt::run(check, verbose),
-        DevCommand::UpdateLints { print_only, check } => {
-            if print_only {
-                update_lints::print_lints();
-            } else if check {
-                update_lints::update(utils::UpdateMode::Check);
-            } else {
-                update_lints::update(utils::UpdateMode::Change);
-            }
-        },
+        DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)),
         DevCommand::NewLint {
             pass,
             name,
             category,
             r#type,
             msrv,
-        } => match new_lint::create(pass, &name, &category, r#type.as_deref(), msrv) {
+        } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) {
             Ok(()) => update_lints::update(utils::UpdateMode::Change),
             Err(e) => eprintln!("Unable to create lint: {e}"),
         },
@@ -79,13 +78,18 @@ fn main() {
             old_name,
             new_name,
             uplift,
-        } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
-        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, &reason),
+        } => rename_lint::rename(
+            clippy.version,
+            &old_name,
+            new_name.as_ref().unwrap_or(&old_name),
+            uplift,
+        ),
+        DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason),
         DevCommand::Sync(SyncCommand { subcommand }) => match subcommand {
             SyncSubcommand::UpdateNightly => sync::update_nightly(),
         },
         DevCommand::Release(ReleaseCommand { subcommand }) => match subcommand {
-            ReleaseSubcommand::BumpVersion => release::bump_version(),
+            ReleaseSubcommand::BumpVersion => release::bump_version(clippy.version),
         },
     }
 }
@@ -136,11 +140,6 @@ enum DevCommand {
     /// * all lints are registered in the lint store
     UpdateLints {
         #[arg(long)]
-        /// Print a table of lints to STDOUT
-        ///
-        /// This does not include deprecated and internal lints. (Does not modify any files)
-        print_only: bool,
-        #[arg(long)]
         /// Checks that `cargo dev update_lints` has been run. Used on CI.
         check: bool,
     },
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 96e12706c9e..4121daa85e6 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -1,4 +1,4 @@
-use crate::utils::{clippy_project_root, clippy_version};
+use crate::utils::{RustSearcher, Token, Version};
 use clap::ValueEnum;
 use indoc::{formatdoc, writedoc};
 use std::fmt::{self, Write as _};
@@ -22,11 +22,11 @@ impl fmt::Display for Pass {
 }
 
 struct LintData<'a> {
+    clippy_version: Version,
     pass: Pass,
     name: &'a str,
     category: &'a str,
     ty: Option<&'a str>,
-    project_root: PathBuf,
 }
 
 trait Context {
@@ -50,18 +50,25 @@ impl<T> Context for io::Result<T> {
 /// # Errors
 ///
 /// This function errors out if the files couldn't be created or written to.
-pub fn create(pass: Pass, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> {
+pub fn create(
+    clippy_version: Version,
+    pass: Pass,
+    name: &str,
+    category: &str,
+    mut ty: Option<&str>,
+    msrv: bool,
+) -> io::Result<()> {
     if category == "cargo" && ty.is_none() {
         // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo`
         ty = Some("cargo");
     }
 
     let lint = LintData {
+        clippy_version,
         pass,
         name,
         category,
         ty,
-        project_root: clippy_project_root(),
     };
 
     create_lint(&lint, msrv).context("Unable to create lint implementation")?;
@@ -88,7 +95,7 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
     } else {
         let lint_contents = get_lint_file_contents(lint, enable_msrv);
         let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
-        write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())?;
+        write_file(&lint_path, lint_contents.as_bytes())?;
         println!("Generated lint file: `{lint_path}`");
 
         Ok(())
@@ -115,8 +122,7 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> {
     }
 
     if lint.category == "cargo" {
-        let relative_test_dir = format!("tests/ui-cargo/{}", lint.name);
-        let test_dir = lint.project_root.join(&relative_test_dir);
+        let test_dir = format!("tests/ui-cargo/{}", lint.name);
         fs::create_dir(&test_dir)?;
 
         create_project_layout(
@@ -134,11 +140,11 @@ fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> {
             false,
         )?;
 
-        println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
+        println!("Generated test directories: `{test_dir}/pass`, `{test_dir}/fail`");
     } else {
         let test_path = format!("tests/ui/{}.rs", lint.name);
         let test_contents = get_test_file_contents(lint.name, msrv);
-        write_file(lint.project_root.join(&test_path), test_contents)?;
+        write_file(&test_path, test_contents)?;
 
         println!("Generated test file: `{test_path}`");
     }
@@ -193,11 +199,6 @@ fn to_camel_case(name: &str) -> String {
         .collect()
 }
 
-pub(crate) fn get_stabilization_version() -> String {
-    let (minor, patch) = clippy_version();
-    format!("{minor}.{patch}.0")
-}
-
 fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
     let mut test = formatdoc!(
         r"
@@ -292,7 +293,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
         );
     }
 
-    let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
+    let _: fmt::Result = writeln!(
+        result,
+        "{}",
+        get_lint_declaration(lint.clippy_version, &name_upper, category)
+    );
 
     if enable_msrv {
         let _: fmt::Result = writedoc!(
@@ -330,7 +335,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
     result
 }
 
-fn get_lint_declaration(name_upper: &str, category: &str) -> String {
+fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> String {
     let justification_heading = if category == "restriction" {
         "Why restrict this?"
     } else {
@@ -355,9 +360,8 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String {
                 pub {name_upper},
                 {category},
                 "default lint description"
-            }}
-        "#,
-        get_stabilization_version(),
+            }}"#,
+        version.rust_display(),
     )
 }
 
@@ -371,7 +375,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
         _ => {},
     }
 
-    let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}"));
+    let ty_dir = PathBuf::from(format!("clippy_lints/src/{ty}"));
     assert!(
         ty_dir.exists() && ty_dir.is_dir(),
         "Directory `{}` does not exist!",
@@ -441,95 +445,25 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
 
 #[allow(clippy::too_many_lines)]
 fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
-    use super::update_lints::{LintDeclSearchResult, match_tokens};
-    use rustc_lexer::TokenKind;
-
     let lint_name_upper = lint.name.to_uppercase();
 
     let mut file_contents = fs::read_to_string(path)?;
     assert!(
-        !file_contents.contains(&lint_name_upper),
+        !file_contents.contains(&format!("pub {lint_name_upper},")),
         "Lint `{}` already defined in `{}`",
         lint.name,
         path.display()
     );
 
-    let mut offset = 0usize;
-    let mut last_decl_curly_offset = None;
-    let mut lint_context = None;
-
-    let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
-        let range = offset..offset + t.len as usize;
-        offset = range.end;
-
-        LintDeclSearchResult {
-            token_kind: t.kind,
-            content: &file_contents[range.clone()],
-            range,
-        }
-    });
-
-    // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
-    while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
-        let mut iter = iter
-            .by_ref()
-            .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
-
-        match content {
-            "declare_clippy_lint" => {
-                // matches `!{`
-                match_tokens!(iter, Bang OpenBrace);
-                if let Some(LintDeclSearchResult { range, .. }) =
-                    iter.find(|result| result.token_kind == TokenKind::CloseBrace)
-                {
-                    last_decl_curly_offset = Some(range.end);
-                }
-            },
-            "impl" => {
-                let mut token = iter.next();
-                match token {
-                    // matches <'foo>
-                    Some(LintDeclSearchResult {
-                        token_kind: TokenKind::Lt,
-                        ..
-                    }) => {
-                        match_tokens!(iter, Lifetime { .. } Gt);
-                        token = iter.next();
-                    },
-                    None => break,
-                    _ => {},
-                }
-
-                if let Some(LintDeclSearchResult {
-                    token_kind: TokenKind::Ident,
-                    content,
-                    ..
-                }) = token
-                {
-                    // Get the appropriate lint context struct
-                    lint_context = match content {
-                        "LateLintPass" => Some("LateContext"),
-                        "EarlyLintPass" => Some("EarlyContext"),
-                        _ => continue,
-                    };
-                }
-            },
-            _ => {},
-        }
-    }
-
-    drop(iter);
-
-    let last_decl_curly_offset =
-        last_decl_curly_offset.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display()));
-    let lint_context =
-        lint_context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display()));
+    let (lint_context, lint_decl_end) = parse_mod_file(path, &file_contents);
 
     // Add the lint declaration to `mod.rs`
-    file_contents.replace_range(
-        // Remove the trailing newline, which should always be present
-        last_decl_curly_offset..=last_decl_curly_offset,
-        &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)),
+    file_contents.insert_str(
+        lint_decl_end,
+        &format!(
+            "\n\n{}",
+            get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category)
+        ),
     );
 
     // Add the lint to `impl_lint_pass`/`declare_lint_pass`
@@ -580,6 +514,41 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
     Ok(lint_context)
 }
 
+// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
+fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) {
+    #[allow(clippy::enum_glob_use)]
+    use Token::*;
+
+    let mut context = None;
+    let mut decl_end = None;
+    let mut searcher = RustSearcher::new(contents);
+    while let Some(name) = searcher.find_capture_token(CaptureIdent) {
+        match name {
+            "declare_clippy_lint" => {
+                if searcher.match_tokens(&[Bang, OpenBrace], &mut []) && searcher.find_token(CloseBrace) {
+                    decl_end = Some(searcher.pos());
+                }
+            },
+            "impl" => {
+                let mut capture = "";
+                if searcher.match_tokens(&[Lt, Lifetime, Gt, CaptureIdent], &mut [&mut capture]) {
+                    match capture {
+                        "LateLintPass" => context = Some("LateContext"),
+                        "EarlyLintPass" => context = Some("EarlyContext"),
+                        _ => {},
+                    }
+                }
+            },
+            _ => {},
+        }
+    }
+
+    (
+        context.unwrap_or_else(|| panic!("No lint pass implementation found in `{}`", path.display())),
+        decl_end.unwrap_or_else(|| panic!("No lint declarations found in `{}`", path.display())) as usize,
+    )
+}
+
 #[test]
 fn test_camel_case() {
     let s = "a_lint";
diff --git a/src/tools/clippy/clippy_dev/src/release.rs b/src/tools/clippy/clippy_dev/src/release.rs
index ac755168701..d3b1a7ff320 100644
--- a/src/tools/clippy/clippy_dev/src/release.rs
+++ b/src/tools/clippy/clippy_dev/src/release.rs
@@ -1,27 +1,27 @@
+use crate::utils::{FileUpdater, Version, update_text_region_fn};
 use std::fmt::Write;
-use std::path::Path;
 
-use crate::utils::{UpdateMode, clippy_version, replace_region_in_file};
-
-const CARGO_TOML_FILES: [&str; 4] = [
+static CARGO_TOML_FILES: &[&str] = &[
     "clippy_config/Cargo.toml",
     "clippy_lints/Cargo.toml",
     "clippy_utils/Cargo.toml",
     "Cargo.toml",
 ];
 
-pub fn bump_version() {
-    let (minor, mut patch) = clippy_version();
-    patch += 1;
-    for file in &CARGO_TOML_FILES {
-        replace_region_in_file(
-            UpdateMode::Change,
-            Path::new(file),
-            "# begin autogenerated version\n",
-            "# end autogenerated version",
-            |res| {
-                writeln!(res, "version = \"0.{minor}.{patch}\"").unwrap();
-            },
+pub fn bump_version(mut version: Version) {
+    version.minor += 1;
+
+    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();
+                },
+            ),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/rename_lint.rs b/src/tools/clippy/clippy_dev/src/rename_lint.rs
new file mode 100644
index 00000000000..9e7e5d97f02
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/rename_lint.rs
@@ -0,0 +1,194 @@
+use crate::update_lints::{
+    DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files,
+    read_deprecated_lints,
+};
+use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file};
+use std::ffi::OsStr;
+use std::path::Path;
+use walkdir::WalkDir;
+
+/// Runs the `rename_lint` command.
+///
+/// This does the following:
+/// * Adds an entry to `renamed_lints.rs`.
+/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`).
+/// * Renames the lint struct to the new name.
+/// * Renames the module containing the lint struct to the new name if it shares a name with the
+///   lint.
+///
+/// # Panics
+/// Panics for the following conditions:
+/// * If a file path could not read from or then written to
+/// * 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)]
+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");
+    }
+    if let Some((prefix, _)) = new_name.split_once("::") {
+        panic!("`{new_name}` should not contain the `{prefix}` prefix");
+    }
+
+    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 old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
+
+    let lint = RenamedLint {
+        old_name: format!("clippy::{old_name}"),
+        new_name: if uplift {
+            new_name.into()
+        } else {
+            format!("clippy::{new_name}")
+        },
+    };
+
+    // 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());
+    }
+
+    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))
+    });
+
+    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")),
+            );
+        }
+
+        // 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();
+            }
+            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)),
+            )
+        {
+            // 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);
+            }
+            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
+            replacements.as_slice()
+        } 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());
+            }
+        }
+
+        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
+        println!("{old_name} has been successfully renamed");
+    }
+
+    println!("note: `cargo uitest` still needs to be run to update the test results");
+}
diff --git a/src/tools/clippy/clippy_dev/src/sync.rs b/src/tools/clippy/clippy_dev/src/sync.rs
index a6b65e561c2..c699b0d7b95 100644
--- a/src/tools/clippy/clippy_dev/src/sync.rs
+++ b/src/tools/clippy/clippy_dev/src/sync.rs
@@ -1,33 +1,18 @@
-use std::fmt::Write;
-use std::path::Path;
-
+use crate::utils::{FileUpdater, update_text_region_fn};
 use chrono::offset::Utc;
-
-use crate::utils::{UpdateMode, replace_region_in_file};
+use std::fmt::Write;
 
 pub fn update_nightly() {
-    // Update rust-toolchain nightly version
     let date = Utc::now().format("%Y-%m-%d").to_string();
-    replace_region_in_file(
-        UpdateMode::Change,
-        Path::new("rust-toolchain.toml"),
+    let update = &mut update_text_region_fn(
         "# begin autogenerated nightly\n",
         "# end autogenerated nightly",
-        |res| {
-            writeln!(res, "channel = \"nightly-{date}\"").unwrap();
+        |dst| {
+            writeln!(dst, "channel = \"nightly-{date}\"").unwrap();
         },
     );
 
-    // Update clippy_utils nightly version
-    replace_region_in_file(
-        UpdateMode::Change,
-        Path::new("clippy_utils/README.md"),
-        "<!-- begin autogenerated nightly -->\n",
-        "<!-- end autogenerated nightly -->",
-        |res| {
-            writeln!(res, "```").unwrap();
-            writeln!(res, "nightly-{date}").unwrap();
-            writeln!(res, "```").unwrap();
-        },
-    );
+    let mut updater = FileUpdater::default();
+    updater.update_file("rust-toolchain.toml", update);
+    updater.update_file("clippy_utils/README.md", update);
 }
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index d848a97f86d..0c861b72935 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,15 +1,12 @@
-use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file};
-use aho_corasick::AhoCorasickBuilder;
+use crate::utils::{
+    File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn,
+};
 use itertools::Itertools;
-use rustc_lexer::{LiteralKind, TokenKind, tokenize};
-use rustc_literal_escaper::{Mode, unescape_unicode};
-use std::collections::{HashMap, HashSet};
-use std::ffi::OsStr;
-use std::fmt::{self, Write};
-use std::fs::{self, OpenOptions};
-use std::io::{self, Read, Seek, Write as _};
+use std::collections::HashSet;
+use std::fmt::Write;
+use std::fs::OpenOptions;
 use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use walkdir::{DirEntry, WalkDir};
 
 const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -28,839 +25,322 @@ 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, deprecated_lints, renamed_lints) = gather_all();
-    generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
+    let lints = find_lint_decls();
+    let DeprecatedLints {
+        renamed, deprecated, ..
+    } = read_deprecated_lints();
+    generate_lint_files(update_mode, &lints, &deprecated, &renamed);
 }
 
-fn generate_lint_files(
+pub fn generate_lint_files(
     update_mode: UpdateMode,
     lints: &[Lint],
-    deprecated_lints: &[DeprecatedLint],
-    renamed_lints: &[RenamedLint],
+    deprecated: &[DeprecatedLint],
+    renamed: &[RenamedLint],
 ) {
-    let mut lints = lints.to_owned();
-    lints.sort_by_key(|lint| lint.name.clone());
-
-    replace_region_in_file(
-        update_mode,
-        Path::new("README.md"),
-        "[There are over ",
-        " lints included in this crate!]",
-        |res| {
-            write!(res, "{}", round_to_fifty(lints.len())).unwrap();
-        },
-    );
-
-    replace_region_in_file(
-        update_mode,
-        Path::new("book/src/README.md"),
-        "[There are over ",
-        " lints included in this crate!]",
-        |res| {
-            write!(res, "{}", round_to_fifty(lints.len())).unwrap();
-        },
-    );
-
-    replace_region_in_file(
-        update_mode,
-        Path::new("CHANGELOG.md"),
-        "<!-- begin autogenerated links to lint list -->\n",
-        "<!-- end autogenerated links to lint list -->",
-        |res| {
-            for lint in lints
-                .iter()
-                .map(|l| &*l.name)
-                .chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
-                .chain(renamed_lints.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
-                .sorted()
-            {
-                writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
-            }
-        },
-    );
-
-    // This has to be in lib.rs, otherwise rustfmt doesn't work
-    replace_region_in_file(
-        update_mode,
-        Path::new("clippy_lints/src/lib.rs"),
-        "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n",
-        "// end lints modules, do not remove this comment, it’s used in `update_lints`",
-        |res| {
-            for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() {
-                writeln!(res, "mod {lint_mod};").unwrap();
-            }
-        },
-    );
-
-    process_file(
-        "clippy_lints/src/declared_lints.rs",
+    FileUpdater::default().update_files_checked(
+        "cargo dev update_lints",
         update_mode,
-        &gen_declared_lints(lints.iter()),
-    );
-
-    let content = gen_deprecated_lints_test(deprecated_lints);
-    process_file("tests/ui/deprecated.rs", update_mode, &content);
-
-    let content = gen_renamed_lints_test(renamed_lints);
-    process_file("tests/ui/rename.rs", update_mode, &content);
-}
-
-pub fn print_lints() {
-    let (lints, _, _) = gather_all();
-    let lint_count = lints.len();
-    let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter());
-
-    for (lint_group, mut lints) in grouped_by_lint_group {
-        println!("\n## {lint_group}");
-
-        lints.sort_by_key(|l| l.name.clone());
-
-        for lint in lints {
-            println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc);
-        }
-    }
-
-    println!("there are {lint_count} lints");
-}
-
-/// Runs the `rename_lint` command.
-///
-/// This does the following:
-/// * Adds an entry to `renamed_lints.rs`.
-/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`).
-/// * Renames the lint struct to the new name.
-/// * Renames the module containing the lint struct to the new name if it shares a name with the
-///   lint.
-///
-/// # Panics
-/// Panics for the following conditions:
-/// * If a file path could not read from or then written to
-/// * 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)]
-pub fn rename(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");
-    }
-    if let Some((prefix, _)) = new_name.split_once("::") {
-        panic!("`{new_name}` should not contain the `{prefix}` prefix");
-    }
-
-    let (mut lints, deprecated_lints, mut renamed_lints) = gather_all();
-    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 old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
-
-    let lint = RenamedLint {
-        old_name: format!("clippy::{old_name}"),
-        new_name: if uplift {
-            new_name.into()
-        } else {
-            format!("clippy::{new_name}")
-        },
-    };
-
-    // 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`)
-    for file in WalkDir::new(clippy_project_root())
-        .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"))
-        })
-    {
-        rewrite_file(file.path(), |s| {
-            replace_ident_like(s, &[(&lint.old_name, &lint.new_name)])
-        });
-    }
-
-    let version = crate::new_lint::get_stabilization_version();
-    rewrite_file(Path::new("clippy_lints/src/deprecated_lints.rs"), |s| {
-        insert_at_marker(
-            s,
-            "// end renamed lints. used by `cargo dev rename_lint`",
-            &format!(
-                "#[clippy::version = \"{version}\"]\n    \
-                (\"{}\", \"{}\"),\n    ",
-                lint.old_name, lint.new_name,
+        &mut [
+            (
+                "README.md",
+                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+                }),
             ),
-        )
-    });
-
-    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))
-    });
-
-    if uplift {
-        write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&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 {
-        write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&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")),
-            );
-        }
-
-        // 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();
-            }
-            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)),
-            )
-        {
-            // 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);
-            }
-            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
-            replacements.as_slice()
-        } 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.
-        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("deprecated_lints.rs"))
-        {
-            rewrite_file(file.path(), |s| replace_ident_like(s, replacements));
-        }
-
-        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
-        println!("{old_name} has been successfully renamed");
-    }
-
-    println!("note: `cargo uitest` still needs to be run to update the test results");
-}
-
-/// Runs the `deprecate` command
-///
-/// This does the following:
-/// * Adds an entry to `deprecated_lints.rs`.
-/// * Removes the lint declaration (and the entire file if applicable)
-///
-/// # Panics
-///
-/// If a file path could not read from or written to
-pub fn deprecate(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..];
-
-    let (mut lints, mut deprecated_lints, renamed_lints) = gather_all();
-    let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else {
-        eprintln!("error: failed to find lint `{name}`");
-        return;
-    };
-
-    let mod_path = {
-        let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
-        if mod_path.is_dir() {
-            mod_path = mod_path.join("mod");
-        }
-
-        mod_path.set_extension("rs");
-        mod_path
-    };
-
-    let deprecated_lints_path = &*clippy_project_root().join("clippy_lints/src/deprecated_lints.rs");
-
-    if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) {
-        let version = crate::new_lint::get_stabilization_version();
-        rewrite_file(deprecated_lints_path, |s| {
-            insert_at_marker(
-                s,
-                "// end deprecated lints. used by `cargo dev deprecate_lint`",
-                &format!("#[clippy::version = \"{version}\"]\n    (\"{prefixed_name}\", \"{reason}\"),\n    ",),
-            )
-        });
-
-        deprecated_lints.push(DeprecatedLint {
-            name: prefixed_name,
-            reason: reason.into(),
-        });
-
-        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");
-    } else {
-        eprintln!("error: lint not found");
-    }
-}
-
-fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> {
-    fn remove_lint(name: &str, lints: &mut Vec<Lint>) {
-        lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos));
-    }
-
-    fn remove_test_assets(name: &str) {
-        let test_file_stem = format!("tests/ui/{name}");
-        let path = Path::new(&test_file_stem);
-
-        // Some lints have their own directories, delete them
-        if path.is_dir() {
-            let _ = fs::remove_dir_all(path);
-            return;
-        }
-
-        // Remove all related test files
-        let _ = fs::remove_file(path.with_extension("rs"));
-        let _ = fs::remove_file(path.with_extension("stderr"));
-        let _ = fs::remove_file(path.with_extension("fixed"));
-    }
-
-    fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
-        let impl_lint_pass_start = content.find("impl_lint_pass!").unwrap_or_else(|| {
-            content
-                .find("declare_lint_pass!")
-                .unwrap_or_else(|| panic!("failed to find `impl_lint_pass`"))
-        });
-        let mut impl_lint_pass_end = content[impl_lint_pass_start..]
-            .find(']')
-            .expect("failed to find `impl_lint_pass` terminator");
-
-        impl_lint_pass_end += impl_lint_pass_start;
-        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) {
-            let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len());
-            for c in content[lint_name_end..impl_lint_pass_end].chars() {
-                // Remove trailing whitespace
-                if c == ',' || c.is_whitespace() {
-                    lint_name_end += 1;
-                } else {
-                    break;
+            (
+                "book/src/README.md",
+                &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| {
+                    write!(dst, "{}", round_to_fifty(lints.len())).unwrap();
+                }),
+            ),
+            (
+                "CHANGELOG.md",
+                &mut update_text_region_fn(
+                    "<!-- begin autogenerated links to lint list -->\n",
+                    "<!-- end autogenerated links to lint list -->",
+                    |dst| {
+                        for lint in lints
+                            .iter()
+                            .map(|l| &*l.name)
+                            .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
+                            .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::")))
+                            .sorted()
+                        {
+                            writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
+                        }
+                    },
+                ),
+            ),
+            (
+                "clippy_lints/src/lib.rs",
+                &mut update_text_region_fn(
+                    "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n",
+                    "// end lints modules, do not remove this comment, it’s used in `update_lints`",
+                    |dst| {
+                        for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() {
+                            writeln!(dst, "mod {lint_mod};").unwrap();
+                        }
+                    },
+                ),
+            ),
+            ("clippy_lints/src/declared_lints.rs", &mut |_, src, dst| {
+                dst.push_str(GENERATED_FILE_COMMENT);
+                dst.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
+                for (module_name, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() {
+                    writeln!(dst, "    crate::{module_name}::{lint_name}_INFO,").unwrap();
                 }
-            }
-
-            content.replace_range(impl_lint_pass_start + lint_name_pos..lint_name_end, "");
-        }
-    }
-
-    if path.exists()
-        && let Some(lint) = lints.iter().find(|l| l.name == name)
-    {
-        if lint.module == name {
-            // The lint name is the same as the file, we can just delete the entire file
-            fs::remove_file(path)?;
-        } else {
-            // We can't delete the entire file, just remove the declaration
-
-            if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
-                // Remove clippy_lints/src/some_mod/some_lint.rs
-                let mut lint_mod_path = path.to_path_buf();
-                lint_mod_path.set_file_name(name);
-                lint_mod_path.set_extension("rs");
-
-                let _ = fs::remove_file(lint_mod_path);
-            }
-
-            let mut content =
-                fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
-
-            eprintln!(
-                "warn: you will have to manually remove any code related to `{name}` from `{}`",
-                path.display()
-            );
-
-            assert!(
-                content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
-                "error: `{}` does not contain lint `{}`'s declaration",
-                path.display(),
-                lint.name
-            );
-
-            // Remove lint declaration (declare_clippy_lint!)
-            content.replace_range(lint.declaration_range.clone(), "");
-
-            // Remove the module declaration (mod xyz;)
-            let mod_decl = format!("\nmod {name};");
-            content = content.replacen(&mod_decl, "", 1);
-
-            remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
-            fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
-        }
-
-        remove_test_assets(name);
-        remove_lint(name, lints);
-        return Ok(true);
-    }
-
-    Ok(false)
-}
-
-/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
-/// were no replacements.
-fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<String> {
-    fn is_ident_char(c: u8) -> bool {
-        matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
-    }
-
-    let searcher = AhoCorasickBuilder::new()
-        .match_kind(aho_corasick::MatchKind::LeftmostLongest)
-        .build(replacements.iter().map(|&(x, _)| x.as_bytes()))
-        .unwrap();
-
-    let mut result = String::with_capacity(contents.len() + 1024);
-    let mut pos = 0;
-    let mut edited = false;
-    for m in searcher.find_iter(contents) {
-        let (old, new) = replacements[m.pattern()];
-        result.push_str(&contents[pos..m.start()]);
-        result.push_str(
-            if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
-                && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0))
-            {
-                edited = true;
-                new
-            } else {
-                old
-            },
-        );
-        pos = m.end();
-    }
-    result.push_str(&contents[pos..]);
-    edited.then_some(result)
+                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 {
+                    writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
+                }
+                dst.push_str("\nfn main() {}\n");
+                UpdateStatus::from_changed(src != dst)
+            }),
+            ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)),
+        ],
+    );
 }
 
 fn round_to_fifty(count: usize) -> usize {
     count / 50 * 50
 }
 
-fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str) {
-    if update_mode == UpdateMode::Check {
-        let old_content =
-            fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display()));
-        if content != old_content {
-            exit_with_failure();
-        }
-    } else {
-        fs::write(&path, content.as_bytes())
-            .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display()));
-    }
-}
-
 /// Lint data parsed from the Clippy source code.
 #[derive(Clone, PartialEq, Eq, Debug)]
-struct Lint {
-    name: String,
-    group: String,
-    desc: String,
-    module: String,
-    declaration_range: Range<usize>,
-}
-
-impl Lint {
-    #[must_use]
-    fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self {
-        Self {
-            name: name.to_lowercase(),
-            group: group.into(),
-            desc: remove_line_splices(desc),
-            module: module.into(),
-            declaration_range,
-        }
-    }
-
-    /// Returns the lints in a `HashMap`, grouped by the different lint groups
-    #[must_use]
-    fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
-        lints.map(|lint| (lint.group.to_string(), lint)).into_group_map()
-    }
+pub struct Lint {
+    pub name: String,
+    pub group: String,
+    pub module: String,
+    pub declaration_range: Range<usize>,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
-struct DeprecatedLint {
-    name: String,
-    reason: String,
-}
-impl DeprecatedLint {
-    fn new(name: &str, reason: &str) -> Self {
-        Self {
-            name: remove_line_splices(name),
-            reason: remove_line_splices(reason),
-        }
-    }
+pub struct DeprecatedLint {
+    pub name: String,
+    pub reason: String,
 }
 
-struct RenamedLint {
-    old_name: String,
-    new_name: String,
-}
-impl RenamedLint {
-    fn new(old_name: &str, new_name: &str) -> Self {
-        Self {
-            old_name: remove_line_splices(old_name),
-            new_name: remove_line_splices(new_name),
-        }
-    }
+pub struct RenamedLint {
+    pub old_name: String,
+    pub new_name: String,
 }
 
-/// Generates the code for registering lints
-#[must_use]
-fn gen_declared_lints<'a>(lints: impl Iterator<Item = &'a Lint>) -> String {
-    let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect();
-    details.sort_unstable();
-
-    let mut output = GENERATED_FILE_COMMENT.to_string();
-    output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
-
-    for (module_name, lint_name) in details {
-        let _: fmt::Result = writeln!(output, "    crate::{module_name}::{lint_name}_INFO,");
-    }
-    output.push_str("];\n");
-
-    output
-}
-
-fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
-    let mut res: String = GENERATED_FILE_COMMENT.into();
-    for lint in lints {
-        writeln!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap();
-    }
-    res.push_str("\nfn main() {}\n");
-    res
-}
-
-fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
-    let mut seen_lints = HashSet::new();
-    let mut res: String = GENERATED_FILE_COMMENT.into();
-
-    res.push_str("#![allow(clippy::duplicated_attributes)]\n");
-    for lint in lints {
-        if seen_lints.insert(&lint.new_name) {
-            writeln!(res, "#![allow({})]", lint.new_name).unwrap();
+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!(res, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_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)
     }
-    res.push_str("\nfn main() {}\n");
-    res
 }
 
-/// Gathers all lints defined in `clippy_lints/src`
-fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
+/// Finds all lint declarations (`declare_clippy_lint!`)
+#[must_use]
+pub fn find_lint_decls() -> Vec<Lint> {
     let mut lints = Vec::with_capacity(1000);
-    let mut deprecated_lints = Vec::with_capacity(50);
-    let mut renamed_lints = Vec::with_capacity(50);
-
-    for (rel_path, file) in clippy_lints_src_files() {
-        let path = file.path();
-        let contents =
-            fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
-        let module = rel_path
-            .components()
-            .map(|c| c.as_os_str().to_str().unwrap())
-            .collect::<Vec<_>>()
-            .join("::");
+    let mut contents = String::new();
+    for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
+        parse_clippy_lint_decls(
+            File::open_read_to_cleared_string(file.path(), &mut contents),
+            &module,
+            &mut lints,
+        );
+    }
+    lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
+    lints
+}
 
-        // If the lints are stored in mod.rs, we get the module name from
-        // the containing directory:
-        let module = if let Some(module) = module.strip_suffix("::mod.rs") {
-            module
-        } else {
-            module.strip_suffix(".rs").unwrap_or(&module)
+/// Reads the source files from the given root directory
+fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirEntry, String)> {
+    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),
         };
-
-        if module == "deprecated_lints" {
-            parse_deprecated_contents(&contents, &mut deprecated_lints, &mut renamed_lints);
+        let path = e.path().as_os_str().as_encoded_bytes();
+        if let Some(path) = path.strip_suffix(b".rs")
+            && let Some(path) = path.get("clippy_lints/src/".len()..)
+        {
+            if path == b"lib" {
+                Some((e, String::new()))
+            } else {
+                let path = if let Some(path) = path.strip_suffix(b"mod")
+                    && let Some(path) = path.strip_suffix(b"/").or_else(|| path.strip_suffix(b"\\"))
+                {
+                    path
+                } else {
+                    path
+                };
+                if let Ok(path) = str::from_utf8(path) {
+                    let path = path.replace(['/', '\\'], "::");
+                    Some((e, path))
+                } else {
+                    None
+                }
+            }
         } else {
-            parse_contents(&contents, module, &mut lints);
+            None
         }
-    }
-    (lints, deprecated_lints, renamed_lints)
-}
-
-fn clippy_lints_src_files() -> impl Iterator<Item = (PathBuf, DirEntry)> {
-    let root_path = clippy_project_root().join("clippy_lints/src");
-    let iter = WalkDir::new(&root_path).into_iter();
-    iter.map(Result::unwrap)
-        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
-        .map(move |f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f))
+    })
 }
 
-macro_rules! match_tokens {
-    ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => {
-         {
-            $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult {
-                    token_kind: TokenKind::$token $({$($fields)*})?,
-                    content: $($capture @)? _,
-                    ..
-            }) = $iter.next() else {
-                continue;
-            };)*
-            #[allow(clippy::unused_unit)]
-            { ($($($capture,)?)*) }
+/// Parse a source file looking for `declare_clippy_lint` macro invocations.
+fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec<Lint>) {
+    #[allow(clippy::enum_glob_use)]
+    use Token::*;
+    #[rustfmt::skip]
+    static DECL_TOKENS: &[Token] = &[
+        // !{ /// docs
+        Bang, OpenBrace, AnyDoc,
+        // #[clippy::version = "version"]
+        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
+        // pub NAME, GROUP,
+        Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma,
+    ];
+
+    let mut searcher = RustSearcher::new(contents);
+    while searcher.find_token(Ident("declare_clippy_lint")) {
+        let start = searcher.pos() as usize - "declare_clippy_lint".len();
+        let (mut name, mut group) = ("", "");
+        if searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut group]) && searcher.find_token(CloseBrace) {
+            lints.push(Lint {
+                name: name.to_lowercase(),
+                group: group.into(),
+                module: module.into(),
+                declaration_range: start..searcher.pos() as usize,
+            });
         }
     }
 }
 
-pub(crate) use match_tokens;
-
-pub(crate) struct LintDeclSearchResult<'a> {
-    pub token_kind: TokenKind,
-    pub content: &'a str,
-    pub range: Range<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,
 }
 
-/// Parse a source file looking for `declare_clippy_lint` macro invocations.
-fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
-    let mut offset = 0usize;
-    let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len as usize;
-        offset = range.end;
-
-        LintDeclSearchResult {
-            token_kind: t.kind,
-            content: &contents[range.clone()],
-            range,
-        }
-    });
-
-    while let Some(LintDeclSearchResult { range, .. }) = iter.find(
-        |LintDeclSearchResult {
-             token_kind, content, ..
-         }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
-    ) {
-        let start = range.start;
-        let mut iter = iter
-            .by_ref()
-            .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
-        // matches `!{`
-        match_tokens!(iter, Bang OpenBrace);
-        match iter.next() {
-            // #[clippy::version = "version"] pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Pound,
-                ..
-            }) => {
-                match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
-            },
-            // pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Ident,
-                ..
-            }) => (),
-            _ => continue,
-        }
-
-        let (name, group, desc) = match_tokens!(
-            iter,
-            // LINT_NAME
-            Ident(name) Comma
-            // group,
-            Ident(group) Comma
-            // "description"
-            Literal{..}(desc)
-        );
-
-        if let Some(end) = iter.find_map(|t| {
-            if let LintDeclSearchResult {
-                token_kind: TokenKind::CloseBrace,
-                range,
-                ..
-            } = t
-            {
-                Some(range.end)
-            } else {
-                None
-            }
-        }) {
-            lints.push(Lint::new(name, group, desc, module, start..end));
-        }
-    }
-}
-
-/// Parse a source file looking for `declare_deprecated_lint` macro invocations.
-fn parse_deprecated_contents(contents: &str, deprecated: &mut Vec<DeprecatedLint>, renamed: &mut Vec<RenamedLint>) {
-    let Some((_, contents)) = contents.split_once("\ndeclare_with_version! { DEPRECATED") else {
-        return;
-    };
-    let Some((deprecated_src, renamed_src)) = contents.split_once("\ndeclare_with_version! { RENAMED") else {
-        return;
+#[must_use]
+pub fn read_deprecated_lints() -> DeprecatedLints {
+    #[allow(clippy::enum_glob_use)]
+    use Token::*;
+    #[rustfmt::skip]
+    static DECL_TOKENS: &[Token] = &[
+        // #[clippy::version = "version"]
+        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
+        // ("first", "second"),
+        OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma,
+    ];
+    #[rustfmt::skip]
+    static DEPRECATED_TOKENS: &[Token] = &[
+        // !{ DEPRECATED(DEPRECATED_VERSION) = [
+        Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket,
+    ];
+    #[rustfmt::skip]
+    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,
     };
 
-    for line in deprecated_src.lines() {
-        let mut offset = 0usize;
-        let mut iter = tokenize(line).map(|t| {
-            let range = offset..offset + t.len as usize;
-            offset = range.end;
+    res.file.read_append_to_string(&mut res.contents);
+    let mut searcher = RustSearcher::new(&res.contents);
 
-            LintDeclSearchResult {
-                token_kind: t.kind,
-                content: &line[range.clone()],
-                range,
-            }
-        });
+    // First instance is the macro definition.
+    assert!(
+        searcher.find_token(Ident("declare_with_version")),
+        "error reading deprecated lints"
+    );
 
-        let (name, reason) = match_tokens!(
-            iter,
-            // ("old_name",
-            Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(name) Comma
-            // "new_name"),
-            Whitespace Literal{kind: LiteralKind::Str{..},..}(reason) CloseParen Comma
-        );
-        deprecated.push(DeprecatedLint::new(name, reason));
+    if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) {
+        let mut name = "";
+        let mut reason = "";
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) {
+            res.deprecated.push(DeprecatedLint {
+                name: parse_str_single_line(path.as_ref(), name),
+                reason: parse_str_single_line(path.as_ref(), reason),
+            });
+        }
+    } 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 old_name = "";
+        let mut new_name = "";
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) {
+            res.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),
+            });
+        }
+    } else {
+        panic!("error reading renamed lints");
     }
-    for line in renamed_src.lines() {
-        let mut offset = 0usize;
-        let mut iter = tokenize(line).map(|t| {
-            let range = offset..offset + t.len as usize;
-            offset = range.end;
-
-            LintDeclSearchResult {
-                token_kind: t.kind,
-                content: &line[range.clone()],
-                range,
-            }
-        });
+    // position of the closing `]}` of `declare_with_version`
+    res.renamed_end = searcher.pos();
 
-        let (old_name, new_name) = match_tokens!(
-            iter,
-            // ("old_name",
-            Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(old_name) Comma
-            // "new_name"),
-            Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma
-        );
-        renamed.push(RenamedLint::new(old_name, new_name));
-    }
+    res
 }
 
 /// Removes the line splices and surrounding quotes from a string literal
-fn remove_line_splices(s: &str) -> String {
+fn parse_str_lit(s: &str) -> String {
+    let (s, mode) = if let Some(s) = s.strip_prefix("r") {
+        (s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr)
+    } else {
+        (s, rustc_literal_escaper::Mode::Str)
+    };
     let s = s
-        .strip_prefix('r')
-        .unwrap_or(s)
-        .trim_matches('#')
         .strip_prefix('"')
         .and_then(|s| s.strip_suffix('"'))
         .unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
     let mut res = String::with_capacity(s.len());
-    unescape_unicode(s, Mode::Str, &mut |range, ch| {
-        if ch.is_ok() {
-            res.push_str(&s[range]);
+    rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| {
+        if let Ok(ch) = ch {
+            res.push(ch);
         }
     });
     res
 }
-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, new_name, "create"),
-    }
-    match fs::rename(old_name, new_name) {
-        Ok(()) => true,
-        Err(e) => {
-            drop(fs::remove_file(new_name));
-            if e.kind() == io::ErrorKind::NotFound {
-                false
-            } else {
-                panic_file(e, old_name, "rename");
-            }
-        },
-    }
-}
-
-#[allow(clippy::needless_pass_by_value)]
-fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
-    panic!("failed to {action} file `{}`: {error}", name.display())
-}
-
-fn insert_at_marker(text: &str, marker: &str, new_text: &str) -> Option<String> {
-    let i = text.find(marker)?;
-    let (pre, post) = text.split_at(i);
-    Some([pre, new_text, post].into_iter().collect())
-}
-
-fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
-    let mut file = OpenOptions::new()
-        .write(true)
-        .read(true)
-        .open(path)
-        .unwrap_or_else(|e| panic_file(e, path, "open"));
-    let mut buf = String::new();
-    file.read_to_string(&mut buf)
-        .unwrap_or_else(|e| panic_file(e, path, "read"));
-    if let Some(new_contents) = f(&buf) {
-        file.rewind().unwrap_or_else(|e| panic_file(e, path, "write"));
-        file.write_all(new_contents.as_bytes())
-            .unwrap_or_else(|e| panic_file(e, path, "write"));
-        file.set_len(new_contents.len() as u64)
-            .unwrap_or_else(|e| panic_file(e, path, "write"));
-    }
-}
 
-fn write_file(path: &Path, contents: &str) {
-    fs::write(path, contents).unwrap_or_else(|e| panic_file(e, path, "write"));
+fn parse_str_single_line(path: &Path, s: &str) -> String {
+    let value = parse_str_lit(s);
+    assert!(
+        !value.contains('\n'),
+        "error parsing `{}`: `{s}` should be a single line string",
+        path.display(),
+    );
+    value
 }
 
 #[cfg(test)]
@@ -868,7 +348,7 @@ mod tests {
     use super::*;
 
     #[test]
-    fn test_parse_contents() {
+    fn test_parse_clippy_lint_decls() {
         static CONTENTS: &str = r#"
             declare_clippy_lint! {
                 #[clippy::version = "Hello Clippy!"]
@@ -886,61 +366,25 @@ mod tests {
             }
         "#;
         let mut result = Vec::new();
-        parse_contents(CONTENTS, "module_name", &mut result);
+        parse_clippy_lint_decls(CONTENTS, "module_name", &mut result);
         for r in &mut result {
             r.declaration_range = Range::default();
         }
 
         let expected = vec![
-            Lint::new(
-                "ptr_arg",
-                "style",
-                "\"really long text\"",
-                "module_name",
-                Range::default(),
-            ),
-            Lint::new(
-                "doc_markdown",
-                "pedantic",
-                "\"single line\"",
-                "module_name",
-                Range::default(),
-            ),
+            Lint {
+                name: "ptr_arg".into(),
+                group: "style".into(),
+                module: "module_name".into(),
+                declaration_range: Range::default(),
+            },
+            Lint {
+                name: "doc_markdown".into(),
+                group: "pedantic".into(),
+                module: "module_name".into(),
+                declaration_range: Range::default(),
+            },
         ];
         assert_eq!(expected, result);
     }
-
-    #[test]
-    fn test_by_lint_group() {
-        let lints = vec![
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new(
-                "should_assert_eq2",
-                "group2",
-                "\"abc\"",
-                "module_name",
-                Range::default(),
-            ),
-            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
-        ];
-        let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
-        expected.insert(
-            "group1".to_string(),
-            vec![
-                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
-            ],
-        );
-        expected.insert(
-            "group2".to_string(),
-            vec![Lint::new(
-                "should_assert_eq2",
-                "group2",
-                "\"abc\"",
-                "module_name",
-                Range::default(),
-            )],
-        );
-        assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
-    }
 }
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index 206816398f5..ae2eabc45dd 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -1,12 +1,113 @@
+use aho_corasick::{AhoCorasick, AhoCorasickBuilder};
+use core::fmt::{self, Display};
+use core::slice;
+use core::str::FromStr;
+use rustc_lexer::{self as lexer, FrontmatterAllowed};
+use std::env;
+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::{fs, io};
 
 #[cfg(not(windows))]
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
 #[cfg(windows)]
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
 
+#[derive(Clone, Copy)]
+pub enum FileAction {
+    Open,
+    Read,
+    Write,
+    Create,
+    Rename,
+}
+impl FileAction {
+    fn as_str(self) -> &'static str {
+        match self {
+            Self::Open => "opening",
+            Self::Read => "reading",
+            Self::Write => "writing",
+            Self::Create => "creating",
+            Self::Rename => "renaming",
+        }
+    }
+}
+
+#[cold]
+#[track_caller]
+pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! {
+    panic!("error {} `{}`: {}", action.as_str(), path.display(), *err)
+}
+
+/// Wrapper around `std::fs::File` which panics with a path on failure.
+pub struct File<'a> {
+    pub inner: fs::File,
+    pub path: &'a Path,
+}
+impl<'a> File<'a> {
+    /// Opens a file panicking on failure.
+    #[track_caller]
+    pub fn open(path: &'a (impl AsRef<Path> + ?Sized), options: &mut OpenOptions) -> Self {
+        let path = path.as_ref();
+        match options.open(path) {
+            Ok(inner) => Self { inner, path },
+            Err(e) => panic_file(&e, FileAction::Open, path),
+        }
+    }
+
+    /// Opens a file if it exists, panicking on any other failure.
+    #[track_caller]
+    pub fn open_if_exists(path: &'a (impl AsRef<Path> + ?Sized), options: &mut OpenOptions) -> Option<Self> {
+        let path = path.as_ref();
+        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),
+        }
+    }
+
+    /// Opens and reads a file into a string, panicking of failure.
+    #[track_caller]
+    pub fn open_read_to_cleared_string<'dst>(
+        path: &'a (impl AsRef<Path> + ?Sized),
+        dst: &'dst mut String,
+    ) -> &'dst mut String {
+        Self::open(path, OpenOptions::new().read(true)).read_to_cleared_string(dst)
+    }
+
+    /// Read the entire contents of a file to the given buffer.
+    #[track_caller]
+    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),
+        }
+        dst
+    }
+
+    #[track_caller]
+    pub fn read_to_cleared_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String {
+        dst.clear();
+        self.read_append_to_string(dst)
+    }
+
+    /// Replaces the entire contents of a file.
+    #[track_caller]
+    pub fn replace_contents(&mut self, data: &[u8]) {
+        let res = match self.inner.seek(SeekFrom::Start(0)) {
+            Ok(_) => match self.inner.write_all(data) {
+                Ok(()) => self.inner.set_len(data.len() as u64),
+                Err(e) => Err(e),
+            },
+            Err(e) => Err(e),
+        };
+        if let Err(e) = res {
+            panic_file(&e, FileAction::Write, self.path);
+        }
+    }
+}
+
 /// Returns the path to the `cargo-clippy` binary
 ///
 /// # Panics
@@ -14,34 +115,107 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
 /// Panics if the path of current executable could not be retrieved.
 #[must_use]
 pub fn cargo_clippy_path() -> PathBuf {
-    let mut path = std::env::current_exe().expect("failed to get current executable name");
+    let mut path = env::current_exe().expect("failed to get current executable name");
     path.set_file_name(CARGO_CLIPPY_EXE);
     path
 }
 
-/// Returns the path to the Clippy project directory
-///
-/// # Panics
-///
-/// Panics if the current directory could not be retrieved, there was an error reading any of the
-/// Cargo.toml files or ancestor directory is the clippy root directory
-#[must_use]
-pub fn clippy_project_root() -> PathBuf {
-    let current_dir = std::env::current_dir().unwrap();
-    for path in current_dir.ancestors() {
-        let result = fs::read_to_string(path.join("Cargo.toml"));
-        if let Err(err) = &result
-            && err.kind() == io::ErrorKind::NotFound
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Version {
+    pub major: u16,
+    pub minor: u16,
+}
+impl FromStr for Version {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        if let Some(s) = s.strip_prefix("0.")
+            && let Some((major, minor)) = s.split_once('.')
+            && let Ok(major) = major.parse()
+            && let Ok(minor) = minor.parse()
         {
-            continue;
+            Ok(Self { major, minor })
+        } else {
+            Err(())
+        }
+    }
+}
+impl Version {
+    /// Displays the version as a rust version. i.e. `x.y.0`
+    #[must_use]
+    pub fn rust_display(self) -> impl Display {
+        struct X(Version);
+        impl Display for X {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "{}.{}.0", self.0.major, self.0.minor)
+            }
+        }
+        X(self)
+    }
+
+    /// Displays the version as it should appear in clippy's toml files. i.e. `0.x.y`
+    #[must_use]
+    pub fn toml_display(self) -> impl Display {
+        struct X(Version);
+        impl Display for X {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(f, "0.{}.{}", self.0.major, self.0.minor)
+            }
         }
+        X(self)
+    }
+}
+
+pub struct ClippyInfo {
+    pub path: PathBuf,
+    pub version: Version,
+}
+impl ClippyInfo {
+    #[must_use]
+    pub fn search_for_manifest() -> Self {
+        let mut path = env::current_dir().expect("error reading the working directory");
+        let mut buf = String::new();
+        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();
+                            },
+                            _ => {},
+                        }
+                    }
+                }
 
-        let content = result.unwrap();
-        if content.contains("[package]\nname = \"clippy\"") {
-            return path.to_path_buf();
+                if is_clippy {
+                    let Some(version) = version else {
+                        panic!("error reading clippy version from {}", file.path.display());
+                    };
+                    path.pop();
+                    return ClippyInfo { path, version };
+                }
+            }
+
+            path.pop();
+            assert!(
+                path.pop(),
+                "error finding project root, please run from inside the clippy directory"
+            );
         }
     }
-    panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
 }
 
 /// # Panics
@@ -57,86 +231,396 @@ pub fn exit_if_err(status: io::Result<ExitStatus>) {
     }
 }
 
-pub(crate) fn clippy_version() -> (u32, u32) {
-    fn parse_manifest(contents: &str) -> Option<(u32, u32)> {
-        let version = contents
-            .lines()
-            .filter_map(|l| l.split_once('='))
-            .find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))?;
-        let Some(("0", version)) = version.get(1..version.len() - 1)?.split_once('.') else {
-            return None;
-        };
-        let (minor, patch) = version.split_once('.')?;
-        Some((minor.parse().ok()?, patch.parse().ok()?))
+#[derive(Clone, Copy)]
+pub enum UpdateStatus {
+    Unchanged,
+    Changed,
+}
+impl UpdateStatus {
+    #[must_use]
+    pub fn from_changed(value: bool) -> Self {
+        if value { Self::Changed } else { Self::Unchanged }
+    }
+
+    #[must_use]
+    pub fn is_changed(self) -> bool {
+        matches!(self, Self::Changed)
     }
-    let contents = fs::read_to_string("Cargo.toml").expect("Unable to read `Cargo.toml`");
-    parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy)]
 pub enum UpdateMode {
-    Check,
     Change,
+    Check,
+}
+impl UpdateMode {
+    #[must_use]
+    pub fn from_check(check: bool) -> Self {
+        if check { Self::Check } else { Self::Change }
+    }
 }
 
-pub(crate) fn exit_with_failure() {
-    println!(
-        "Not all lints defined properly. \
-                 Please run `cargo dev update_lints` to make sure all lints are defined properly."
-    );
-    process::exit(1);
+#[derive(Default)]
+pub struct FileUpdater {
+    src_buf: String,
+    dst_buf: String,
 }
+impl FileUpdater {
+    fn update_file_checked_inner(
+        &mut self,
+        tool: &str,
+        mode: UpdateMode,
+        path: &Path,
+        update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
+    ) {
+        let mut file = File::open(path, OpenOptions::new().read(true).write(true));
+        file.read_to_cleared_string(&mut self.src_buf);
+        self.dst_buf.clear();
+        match (mode, update(path, &self.src_buf, &mut self.dst_buf)) {
+            (UpdateMode::Check, UpdateStatus::Changed) => {
+                eprintln!(
+                    "the contents of `{}` are out of date\nplease run `{tool}` to update",
+                    path.display()
+                );
+                process::exit(1);
+            },
+            (UpdateMode::Change, UpdateStatus::Changed) => file.replace_contents(self.dst_buf.as_bytes()),
+            (UpdateMode::Check | UpdateMode::Change, UpdateStatus::Unchanged) => {},
+        }
+    }
 
-/// Replaces a region in a file delimited by two lines matching regexes.
-///
-/// `path` is the relative path to the file on which you want to perform the replacement.
-///
-/// See `replace_region_in_text` for documentation of the other options.
-///
-/// # Panics
-///
-/// Panics if the path could not read or then written
-pub(crate) fn replace_region_in_file(
-    update_mode: UpdateMode,
+    fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) {
+        let mut file = File::open(path, OpenOptions::new().read(true).write(true));
+        file.read_to_cleared_string(&mut self.src_buf);
+        self.dst_buf.clear();
+        if update(path, &self.src_buf, &mut self.dst_buf).is_changed() {
+            file.replace_contents(self.dst_buf.as_bytes());
+        }
+    }
+
+    pub fn update_file_checked(
+        &mut self,
+        tool: &str,
+        mode: UpdateMode,
+        path: impl AsRef<Path>,
+        update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
+    ) {
+        self.update_file_checked_inner(tool, mode, path.as_ref(), update);
+    }
+
+    #[expect(clippy::type_complexity)]
+    pub fn update_files_checked(
+        &mut self,
+        tool: &str,
+        mode: UpdateMode,
+        files: &mut [(
+            impl AsRef<Path>,
+            &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
+        )],
+    ) {
+        for (path, update) in files {
+            self.update_file_checked_inner(tool, mode, path.as_ref(), update);
+        }
+    }
+
+    pub fn update_file(
+        &mut self,
+        path: impl AsRef<Path>,
+        update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus,
+    ) {
+        self.update_file_inner(path.as_ref(), update);
+    }
+}
+
+/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
+/// were found, or the missing delimiter if not.
+pub fn update_text_region(
     path: &Path,
     start: &str,
     end: &str,
-    write_replacement: impl FnMut(&mut String),
-) {
-    let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
-    let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
-        Ok(x) => x,
-        Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
+    src: &str,
+    dst: &mut String,
+    insert: &mut impl FnMut(&mut String),
+) -> UpdateStatus {
+    let Some((src_start, src_end)) = src.split_once(start) else {
+        panic!("`{}` does not contain `{start}`", path.display());
     };
+    let Some((replaced_text, src_end)) = src_end.split_once(end) else {
+        panic!("`{}` does not contain `{end}`", path.display());
+    };
+    dst.push_str(src_start);
+    dst.push_str(start);
+    let new_start = dst.len();
+    insert(dst);
+    let changed = dst[new_start..] != *replaced_text;
+    dst.push_str(end);
+    dst.push_str(src_end);
+    UpdateStatus::from_changed(changed)
+}
+
+pub fn update_text_region_fn(
+    start: &str,
+    end: &str,
+    mut insert: impl FnMut(&mut String),
+) -> impl FnMut(&Path, &str, &mut String) -> UpdateStatus {
+    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),
+    CaptureIdent,
+    LitStr,
+    CaptureLitStr,
+    Bang,
+    CloseBrace,
+    CloseBracket,
+    CloseParen,
+    /// This will consume the first colon even if the second doesn't exist.
+    DoubleColon,
+    Comma,
+    Eq,
+    Lifetime,
+    Lt,
+    Gt,
+    OpenBrace,
+    OpenBracket,
+    OpenParen,
+    Pound,
+}
+
+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]
+    pub fn new(text: &'txt str) -> Self {
+        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,
+            },
+        }
+    }
+
+    #[must_use]
+    pub fn peek_text(&self) -> &'txt str {
+        &self.text[self.pos as usize..(self.pos + self.next_token.len) as usize]
+    }
+
+    #[must_use]
+    pub fn peek(&self) -> lexer::TokenKind {
+        self.next_token.kind
+    }
+
+    #[must_use]
+    pub fn pos(&self) -> u32 {
+        self.pos
+    }
+
+    #[must_use]
+    pub fn at_end(&self) -> bool {
+        self.next_token.kind == lexer::TokenKind::Eof
+    }
+
+    pub fn step(&mut self) {
+        // `next_len` is zero for the sentinel value and the eof marker.
+        self.pos += self.next_token.len;
+        self.next_token = self.cursor.advance_token();
+    }
+
+    /// 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 {
+        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::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. },
+                ) => {
+                    self.step();
+                    if self.at_end() {
+                        // `AnyDoc` always matches.
+                        return true;
+                    }
+                },
+                (Token::AnyDoc, _) => return true,
+                (Token::Bang, lexer::TokenKind::Bang)
+                | (Token::CloseBrace, lexer::TokenKind::CloseBrace)
+                | (Token::CloseBracket, lexer::TokenKind::CloseBracket)
+                | (Token::CloseParen, lexer::TokenKind::CloseParen)
+                | (Token::Comma, lexer::TokenKind::Comma)
+                | (Token::Eq, lexer::TokenKind::Eq)
+                | (Token::Lifetime, lexer::TokenKind::Lifetime { .. })
+                | (Token::Lt, lexer::TokenKind::Lt)
+                | (Token::Gt, lexer::TokenKind::Gt)
+                | (Token::OpenBrace, lexer::TokenKind::OpenBrace)
+                | (Token::OpenBracket, lexer::TokenKind::OpenBracket)
+                | (Token::OpenParen, lexer::TokenKind::OpenParen)
+                | (Token::Pound, lexer::TokenKind::Pound)
+                | (
+                    Token::LitStr,
+                    lexer::TokenKind::Literal {
+                        kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. },
+                        ..
+                    },
+                ) => {
+                    self.step();
+                    return true;
+                },
+                (Token::Ident(x), lexer::TokenKind::Ident) if x == self.peek_text() => {
+                    self.step();
+                    return true;
+                },
+                (Token::DoubleColon, lexer::TokenKind::Colon) => {
+                    self.step();
+                    if !self.at_end() && matches!(self.next_token.kind, lexer::TokenKind::Colon) {
+                        self.step();
+                        return true;
+                    }
+                    return false;
+                },
+                (
+                    Token::CaptureLitStr,
+                    lexer::TokenKind::Literal {
+                        kind: lexer::LiteralKind::Str { terminated: true } | lexer::LiteralKind::RawStr { .. },
+                        ..
+                    },
+                )
+                | (Token::CaptureIdent, lexer::TokenKind::Ident) => {
+                    **captures.next().unwrap() = self.peek_text();
+                    self.step();
+                    return true;
+                },
+                _ => return false,
+            }
+        }
+    }
+
+    #[must_use]
+    pub fn find_token(&mut self, token: Token) -> bool {
+        let mut capture = [].iter_mut();
+        while !self.read_token(token, &mut capture) {
+            self.step();
+            if self.at_end() {
+                return false;
+            }
+        }
+        true
+    }
+
+    #[must_use]
+    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();
+        while !self.read_token(token, &mut capture) {
+            self.step();
+            if self.at_end() {
+                return None;
+            }
+        }
+        Some(res)
+    }
+
+    #[must_use]
+    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))
+    }
+}
 
-    match update_mode {
-        UpdateMode::Check if contents != new_contents => exit_with_failure(),
-        UpdateMode::Check => (),
-        UpdateMode::Change => {
-            if let Err(e) = fs::write(path, new_contents.as_bytes()) {
-                panic!("Cannot write to `{}`: {e}", path.display());
+#[expect(clippy::must_use_candidate)]
+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),
+    }
+    match fs::rename(old_name, new_name) {
+        Ok(()) => true,
+        Err(e) => {
+            drop(fs::remove_file(new_name));
+            if e.kind() == io::ErrorKind::NotFound {
+                false
+            } else {
+                panic_file(&e, FileAction::Rename, old_name);
             }
         },
     }
 }
 
-/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters
-/// were found, or the missing delimiter if not.
-pub(crate) fn replace_region_in_text<'a>(
-    text: &str,
-    start: &'a str,
-    end: &'a str,
-    mut write_replacement: impl FnMut(&mut String),
-) -> Result<String, &'a str> {
-    let (text_start, rest) = text.split_once(start).ok_or(start)?;
-    let (_, text_end) = rest.split_once(end).ok_or(end)?;
-
-    let mut res = String::with_capacity(text.len() + 4096);
-    res.push_str(text_start);
-    res.push_str(start);
-    write_replacement(&mut res);
-    res.push_str(end);
-    res.push_str(text_end);
-
-    Ok(res)
+pub fn write_file(path: &Path, contents: &str) {
+    fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path));
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 20951afccbb..7e3cb404247 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_lints"
 # begin autogenerated version
-version = "0.1.88"
+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"
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/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 9acff676d4f..8b8b42bbf72 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local};
+use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
-use rustc_span::symbol::sym;
 use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
@@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             && ctxt.is_root()
             && let which_trait = match fn_name {
                 sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
-                _ if fn_name.as_str() == "to_owned"
-                    && is_diag_trait_item(cx, fn_id, sym::ToOwned)
-                    && self.msrv.meets(cx, msrvs::CLONE_INTO) =>
+                sym::to_owned
+                    if is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                        && self.msrv.meets(cx, msrvs::CLONE_INTO) =>
                 {
                     CloneTrait::ToOwned
                 },
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             && resolved_assoc_items.in_definition_order().any(|assoc|
                 match which_trait {
                     CloneTrait::Clone => assoc.name() == sym::clone_from,
-                    CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
+                    CloneTrait::ToOwned => assoc.name() == sym::clone_into,
                 }
             )
             && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
index 457692ed5dc..4d64eec25d2 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
@@ -1,17 +1,15 @@
 use super::BLANKET_CLIPPY_RESTRICTION_LINTS;
 use super::utils::extract_clippy_lint;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::sym;
 use rustc_ast::MetaItemInner;
 use rustc_lint::{EarlyContext, Level, LintContext};
+use rustc_span::DUMMY_SP;
 use rustc_span::symbol::Symbol;
-use rustc_span::{DUMMY_SP, sym};
 
 pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) {
     for lint in items {
-        if let Some(lint_name) = extract_clippy_lint(lint)
-            && lint_name.as_str() == "restriction"
-            && name != sym::allow
-        {
+        if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) {
             span_lint_and_help(
                 cx,
                 BLANKET_CLIPPY_RESTRICTION_LINTS,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
index 7fab97d3ea1..0edb50be8c7 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
@@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met
 }
 
 fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) {
-    if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") {
+    if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) {
         span_lint_and_sugg(
             cx,
             DEPRECATED_CLIPPY_CFG_ATTR,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
index 50943b36809..bd6459d6f9d 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
@@ -1,5 +1,6 @@
 use super::DEPRECATED_SEMVER;
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::sym;
 use rustc_ast::{LitKind, MetaItemLit};
 use rustc_lint::EarlyContext;
 use rustc_span::Span;
@@ -7,7 +8,7 @@ use semver::Version;
 
 pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) {
     if let LitKind::Str(is, _) = lit.kind
-        && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok())
+        && (is == sym::TBD || Version::parse(is.as_str()).is_ok())
     {
         return;
     }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index f7f168cb267..9a124298041 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -468,7 +468,7 @@ declare_clippy_lint! {
     /// #[ignore = "Some good reason"]
     /// fn test() {}
     /// ```
-    #[clippy::version = "1.85.0"]
+    #[clippy::version = "1.88.0"]
     pub IGNORE_WITHOUT_REASON,
     pedantic,
     "ignored tests without messages"
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/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index d75b73280e6..4059f9603c3 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -26,16 +26,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
 
                         if namespace.is_none()
                             && matches!(
-                                name.as_str(),
-                                "ambiguous_glob_reexports"
-                                    | "dead_code"
-                                    | "deprecated"
-                                    | "hidden_glob_reexports"
-                                    | "unreachable_pub"
-                                    | "unused"
-                                    | "unused_braces"
-                                    | "unused_import_braces"
-                                    | "unused_imports"
+                                name,
+                                sym::ambiguous_glob_reexports
+                                    | sym::dead_code
+                                    | sym::deprecated
+                                    | sym::hidden_glob_reexports
+                                    | sym::unreachable_pub
+                                    | sym::unused
+                                    | sym::unused_braces
+                                    | sym::unused_import_braces
+                                    | sym::unused_imports
                             )
                         {
                             return;
@@ -43,16 +43,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
 
                         if namespace == Some(sym::clippy)
                             && matches!(
-                                name.as_str(),
-                                "wildcard_imports"
-                                    | "enum_glob_use"
-                                    | "redundant_pub_crate"
-                                    | "macro_use_imports"
-                                    | "unsafe_removed_from_name"
-                                    | "module_name_repetitions"
-                                    | "single_component_path_imports"
-                                    | "disallowed_types"
-                                    | "unused_trait_names"
+                                name,
+                                sym::wildcard_imports
+                                    | sym::enum_glob_use
+                                    | sym::redundant_pub_crate
+                                    | sym::macro_use_imports
+                                    | sym::unsafe_removed_from_name
+                                    | sym::module_name_repetitions
+                                    | sym::single_component_path_imports
+                                    | sym::disallowed_types
+                                    | sym::unused_trait_names
                             )
                         {
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 52d1d5b4c67..31cc004f685 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_config::types::{DisallowedPathWithoutReplacement, create_disallowed_map};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{match_def_path, paths};
+use clippy_utils::paths::{self, PathNS};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_lint::{LateContext, LateLintPass};
@@ -182,6 +182,7 @@ impl AwaitHolding {
         let (def_ids, _) = create_disallowed_map(
             tcx,
             &conf.await_holding_invalid_types,
+            PathNS::Type,
             crate::disallowed_types::def_kind_predicate,
             "type",
             false,
@@ -275,12 +276,10 @@ fn emit_invalid_type(
 }
 
 fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
-    cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id)
-        || cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id)
-        || cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id)
-        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
-        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
-        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
+    match cx.tcx.get_diagnostic_name(def_id) {
+        Some(name) => matches!(name, sym::MutexGuard | sym::RwLockReadGuard | sym::RwLockWriteGuard),
+        None => paths::PARKING_LOT_GUARDS.iter().any(|guard| guard.matches(cx, def_id)),
+    }
 }
 
 fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 4a876b85416..ae36bb76117 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use clippy_utils::sugg::Sugg;
+use clippy_utils::sym;
 use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -73,10 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
             return;
         };
-        let macro_name = cx.tcx.item_name(macro_call.def_id);
-        let eq_macro = match macro_name.as_str() {
-            "assert_eq" | "debug_assert_eq" => true,
-            "assert_ne" | "debug_assert_ne" => false,
+        let eq_macro = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+            Some(sym::assert_eq_macro | sym::debug_assert_eq_macro) => true,
+            Some(sym::assert_ne_macro | sym::debug_assert_ne_macro) => false,
             _ => return,
         };
         let Some((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
@@ -115,6 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
             return;
         }
 
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
         let macro_name = macro_name.as_str();
         let non_eq_mac = &macro_name[..macro_name.len() - 3];
         span_lint_and_then(
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_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 164d3540253..ba31a51f738 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -19,7 +20,7 @@ pub(super) fn check(
     if let ty::Int(from) = cast_from.kind()
         && let ty::Uint(to) = cast_to.kind()
         && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind
-        && method_path.ident.name.as_str() == "abs"
+        && method_path.ident.name == sym::abs
         && msrv.meets(cx, msrvs::UNSIGNED_ABS)
     {
         let span = if from.bit_width() == to.bit_width() {
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 8742f5f1a0e..e92879b853d 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
@@ -1,9 +1,9 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::expr_or_init;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
+use clippy_utils::{expr_or_init, sym};
 use rustc_abi::IntegerType;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::def::{DefKind, Res};
@@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             nbits
         },
         ExprKind::MethodCall(method, _value, [], _) => {
-            if method.ident.name.as_str() == "signum" {
+            if method.ident.name == sym::signum {
                 0 // do not lint if cast comes from a `signum` function
             } else {
                 nbits
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 3fca0f89707..01020f3eee2 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_c_void;
-use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant};
+use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym};
 use rustc_hir::{Expr, ExprKind, GenericArg};
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
 
 use super::CAST_PTR_ALIGNMENT;
 
@@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         );
         lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
     } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind
-        && method_path.ident.name.as_str() == "cast"
+        && method_path.ident.name == sym::cast
         && let Some(generic_args) = method_path.args
         && let [GenericArg::Type(cast_to)] = generic_args.args
         // There probably is no obvious reason to do this, just to be consistent with `as` cases.
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
new file mode 100644
index 00000000000..31cdd078f45
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
@@ -0,0 +1,82 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, GenericArg, Ty};
+use rustc_span::def_id::DefId;
+use rustc_span::{Symbol, sym};
+
+use super::CONFUSING_METHOD_TO_NUMERIC_CAST;
+
+fn get_primitive_ty_name(ty: Ty<'_>) -> Option<&'static str> {
+    match ty.kind() {
+        ty::Char => Some("char"),
+        ty::Int(int) => Some(int.name_str()),
+        ty::Uint(uint) => Some(uint.name_str()),
+        ty::Float(float) => Some(float.name_str()),
+        _ => None,
+    }
+}
+
+fn get_const_name_and_ty_name(
+    cx: &LateContext<'_>,
+    method_name: Symbol,
+    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) {
+        // We get the type on which the `min`/`max` method of the `Ord` trait is implemented.
+        if let [ty] = generics
+            && let Some(ty) = ty.as_type()
+        {
+            get_primitive_ty_name(ty)?
+        } else {
+            return None;
+        }
+    } 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)
+    {
+        ty_name
+    } else {
+        return None;
+    };
+
+    let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" };
+    Some((const_name, ty_name))
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+    // We allow casts from any function type to any function type.
+    match cast_to.kind() {
+        ty::FnDef(..) | ty::FnPtr(..) => return,
+        _ => { /* continue to checks */ },
+    }
+
+    if let ty::FnDef(def_id, generics) = cast_from.kind()
+        && let Some(method_name) = cx.tcx.opt_item_name(*def_id)
+        && let Some((const_name, ty_name)) = get_const_name_and_ty_name(cx, method_name, *def_id, generics.as_slice())
+    {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+        span_lint_and_then(
+            cx,
+            CONFUSING_METHOD_TO_NUMERIC_CAST,
+            expr.span,
+            format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
+            |diag| {
+                diag.span_suggestion_verbose(
+                    expr.span,
+                    "did you mean to use the associated constant?",
+                    format!("{ty_name}::{const_name} as {cast_to}"),
+                    applicability,
+                );
+            },
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
index 8ace27eca89..61dfc0fc042 100644
--- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::is_normalizable;
-use clippy_utils::{expr_or_init, match_def_path, path_def_id, paths, std_or_core};
+use clippy_utils::{expr_or_init, path_def_id, paths, std_or_core};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
@@ -55,7 +54,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) ->
 fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
     if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
         && let Some(fun_id) = path_def_id(cx, fun)
-        && match_def_path(cx, fun_id, &paths::ALIGN_OF)
+        && paths::ALIGN_OF.matches(cx, fun_id)
         && let Some(args) = path.segments.last().and_then(|seg| seg.args)
         && let [GenericArg::Type(generic_ty)] = args.args
     {
@@ -71,12 +70,10 @@ fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned<LitKind>, to: &Ty<'_>)
         return false;
     }
     let to_mid_ty = cx.typeck_results().node_type(to.hir_id);
-    is_normalizable(cx, cx.param_env, to_mid_ty)
-        && cx
-            .tcx
-            .layout_of(cx.typing_env().as_query_input(to_mid_ty))
-            .is_ok_and(|layout| {
-                let align = u128::from(layout.align.abi.bytes());
-                u128::from(val) <= align
-            })
+    cx.tcx
+        .layout_of(cx.typing_env().as_query_input(to_mid_ty))
+        .is_ok_and(|layout| {
+            let align = u128::from(layout.align.abi.bytes());
+            u128::from(val) <= align
+        })
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 76931fce209..daae9a8bb08 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -14,6 +14,7 @@ mod cast_sign_loss;
 mod cast_slice_different_sizes;
 mod cast_slice_from_raw_parts;
 mod char_lit_as_u8;
+mod confusing_method_to_numeric_cast;
 mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
@@ -780,12 +781,38 @@ declare_clippy_lint! {
     /// let aligned = std::ptr::dangling::<u32>();
     /// let mut_ptr: *mut i64 = std::ptr::dangling_mut();
     /// ```
-    #[clippy::version = "1.87.0"]
+    #[clippy::version = "1.88.0"]
     pub MANUAL_DANGLING_PTR,
     style,
     "casting small constant literals to pointers to create dangling pointers"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type.
+    ///
+    /// ### Why restrict this?
+    /// Casting a function pointer to an integer can have surprising results and can occur
+    /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
+    /// low-level with function pointers then you can opt out of casting functions to integers in
+    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+    /// pointer casts in your code.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let _ = u16::max as usize;
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// let _ = u16::MAX as usize;
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub CONFUSING_METHOD_TO_NUMERIC_CAST,
+    suspicious,
+    "casting a primitive method pointer to any integer type"
+}
+
 pub struct Casts {
     msrv: Msrv,
 }
@@ -823,6 +850,7 @@ impl_lint_pass!(Casts => [
     REF_AS_PTR,
     AS_POINTER_UNDERSCORE,
     MANUAL_DANGLING_PTR,
+    CONFUSING_METHOD_TO_NUMERIC_CAST,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -847,6 +875,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
             zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index ae994e94a32..8e8c55cf383 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -8,7 +8,9 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
+use rustc_span::{Symbol, sym};
 use std::ops::ControlFlow;
 
 use super::UNNECESSARY_CAST;
@@ -142,6 +144,33 @@ pub(super) fn check<'tcx>(
     }
 
     if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
+        enum MaybeParenOrBlock {
+            Paren,
+            Block,
+            Nothing,
+        }
+
+        fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            matches!(expr.kind, ExprKind::AddrOf(..))
+                || cx
+                    .typeck_results()
+                    .expr_adjustments(expr)
+                    .first()
+                    .is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_)))
+        }
+
+        fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            const ALLOWED_MACROS: &[Symbol] = &[
+                sym::format_args_macro,
+                sym::assert_eq_macro,
+                sym::debug_assert_eq_macro,
+                sym::assert_ne_macro,
+                sym::debug_assert_ne_macro,
+            ];
+            matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if 
+                cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
+        }
+
         if let Some(id) = path_to_local(cast_expr)
             && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
         {
@@ -150,15 +179,15 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
-        // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof
-        // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us
-        // changing the precedence of operators if the cast expression is followed by an operation
-        // with higher precedence than the unary operator (`(*x as T).foo()` would become
-        // `*x.foo()`, which changes what the `*` applies on).
-        // The same is true if the expression encompassing the cast expression is a unary
-        // expression or an addressof expression.
-        let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
-            || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
+        // Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates
+        // a reference to the temporary while the latter creates a reference to the original value.
+        let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) {
+            Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => {
+                MaybeParenOrBlock::Block
+            },
+            Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren,
+            _ => MaybeParenOrBlock::Nothing,
+        };
 
         span_lint_and_sugg(
             cx,
@@ -166,10 +195,10 @@ pub(super) fn check<'tcx>(
             expr.span,
             format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
             "try",
-            if needs_block {
-                format!("{{ {cast_str} }}")
-            } else {
-                cast_str
+            match surrounding {
+                MaybeParenOrBlock::Paren => format!("({cast_str})"),
+                MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
+                MaybeParenOrBlock::Nothing => cast_str,
             },
             Applicability::MachineApplicable,
         );
diff --git a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
new file mode 100644
index 00000000000..6b239a1541b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
@@ -0,0 +1,100 @@
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::visitors::is_const_evaluatable;
+use clippy_utils::{is_in_const_context, is_mutable, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::impl_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for slice references with cloned references such as `&[f.clone()]`.
+    ///
+    /// ### Why is this bad
+    ///
+    /// A reference does not need to be owned in order to used as a slice.
+    ///
+    /// ### Known problems
+    ///
+    /// This lint does not know whether or not a clone implementation has side effects.
+    ///
+    /// ### Example
+    ///
+    /// ```ignore
+    /// let data = 10;
+    /// let data_ref = &data;
+    /// take_slice(&[data_ref.clone()]);
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// use std::slice;
+    /// let data = 10;
+    /// let data_ref = &data;
+    /// take_slice(slice::from_ref(data_ref));
+    /// ```
+    #[clippy::version = "1.87.0"]
+    pub CLONED_REF_TO_SLICE_REFS,
+    perf,
+    "cloning a reference for slice references"
+}
+
+pub struct ClonedRefToSliceRefs<'a> {
+    msrv: &'a Msrv,
+}
+impl<'a> ClonedRefToSliceRefs<'a> {
+    pub fn new(conf: &'a Conf) -> Self {
+        Self { msrv: &conf.msrv }
+    }
+}
+
+impl_lint_pass!(ClonedRefToSliceRefs<'_> => [CLONED_REF_TO_SLICE_REFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if self.msrv.meets(cx, {
+            if is_in_const_context(cx) {
+                msrvs::CONST_SLICE_FROM_REF
+            } else {
+                msrvs::SLICE_FROM_REF
+            }
+        })
+            // `&[foo.clone()]` expressions
+            && let ExprKind::AddrOf(_, mutability, arr) = &expr.kind
+            // mutable references would have a different meaning
+            && mutability.is_not()
+
+            // check for single item arrays
+            && let ExprKind::Array([item]) = &arr.kind
+
+            // check for clones
+            && let ExprKind::MethodCall(_, val, _, _) = item.kind
+            && is_trait_method(cx, item, sym::Clone)
+
+            // check for immutability or purity
+            && (!is_mutable(cx, val) || is_const_evaluatable(cx, val))
+
+            // get appropriate crate for `slice::from_ref`
+            && let Some(builtin_crate) = clippy_utils::std_or_core(cx)
+        {
+            let mut sugg = Sugg::hir(cx, val, "_");
+            if !cx.typeck_results().expr_ty(val).is_ref() {
+                sugg = sugg.addr();
+            }
+
+            span_lint_and_sugg(
+                cx,
+                CLONED_REF_TO_SLICE_REFS,
+                expr.span,
+                format!("this call to `clone` can be replaced with `{builtin_crate}::slice::from_ref`"),
+                "try",
+                format!("{builtin_crate}::slice::from_ref({sugg})"),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 20fae8a6775..7f6ecea99fb 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -1,11 +1,11 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability};
 use rustc_ast::BinOpKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -78,14 +78,14 @@ declare_clippy_lint! {
 }
 
 pub struct CollapsibleIf {
-    let_chains_enabled: bool,
+    msrv: Msrv,
     lint_commented_code: bool,
 }
 
 impl CollapsibleIf {
-    pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
+    pub fn new(conf: &'static Conf) -> Self {
         Self {
-            let_chains_enabled: tcx.features().let_chains(),
+            msrv: conf.msrv,
             lint_commented_code: conf.lint_commented_code,
         }
     }
@@ -127,7 +127,7 @@ impl CollapsibleIf {
         if let Some(inner) = expr_block(then)
             && cx.tcx.hir_attrs(inner.hir_id).is_empty()
             && let ExprKind::If(check_inner, _, None) = &inner.kind
-            && self.eligible_condition(check_inner)
+            && self.eligible_condition(cx, check_inner)
             && let ctxt = expr.span.ctxt()
             && inner.span.ctxt() == ctxt
             && (self.lint_commented_code || !block_starts_with_comment(cx, then))
@@ -163,8 +163,9 @@ impl CollapsibleIf {
         }
     }
 
-    pub fn eligible_condition(&self, cond: &Expr<'_>) -> bool {
-        self.let_chains_enabled || !matches!(cond.kind, ExprKind::Let(..))
+    fn eligible_condition(&self, cx: &LateContext<'_>, cond: &Expr<'_>) -> bool {
+        !matches!(cond.kind, ExprKind::Let(..))
+            || (cx.tcx.sess.edition().at_least_rust_2024() && self.msrv.meets(cx, msrvs::LET_CHAINS))
     }
 }
 
@@ -180,7 +181,7 @@ impl LateLintPass<'_> for CollapsibleIf {
             {
                 Self::check_collapsible_else_if(cx, then.span, else_);
             } else if else_.is_none()
-                && self.eligible_condition(cond)
+                && self.eligible_condition(cx, cond)
                 && let ExprKind::Block(then, None) = then.kind
             {
                 self.check_collapsible_if_if(cx, expr, cond, then);
@@ -202,13 +203,12 @@ fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
 fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     match block.stmts {
         [] => block.expr,
-        [stmt] => {
-            if let StmtKind::Semi(expr) = stmt.kind {
-                Some(expr)
-            } else {
-                None
-            }
-        },
+        [
+            Stmt {
+                kind: StmtKind::Semi(expr),
+                ..
+            },
+        ] if block.expr.is_none() => Some(expr),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index c2aac7ca090..19f62e8bf79 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
 use rustc_span::symbol::sym;
+use rustc_span::{Span, kw};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
 fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
     if let TokenTree::Token(
         Token {
-            kind: TokenKind::Ident(symbol, _),
+            kind: TokenKind::Ident(kw::Crate, _),
             span,
         },
         _,
     ) = tt
-        && symbol.as_str() == "crate"
     {
         Some(*span)
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 2cccd6ba270..bb825c7655f 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -64,6 +64,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
     crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
     crate::casts::CHAR_LIT_AS_U8_INFO,
+    crate::casts::CONFUSING_METHOD_TO_NUMERIC_CAST_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
@@ -75,6 +76,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::casts::ZERO_PTR_INFO,
     crate::cfg_not_test::CFG_NOT_TEST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
+    crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
     crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
     crate::collapsible_if::COLLAPSIBLE_IF_INFO,
@@ -705,13 +707,9 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO,
     crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
     crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
-    crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
-    crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
-    crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
     crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
     crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
-    crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
     crate::transmute::TRANSMUTE_UNDEFINED_REPR_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 b60c11d79d4..94651538669 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -2,18 +2,18 @@
 // Prefer to use those when possible.
 
 macro_rules! declare_with_version {
-    ($name:ident($name_version:ident): &[$ty:ty] = &[$(
+    ($name:ident($name_version:ident) = [$(
         #[clippy::version = $version:literal]
         $e:expr,
     )*]) => {
-        pub static $name: &[$ty] = &[$($e),*];
+        pub static $name: &[(&str, &str)] = &[$($e),*];
         #[allow(unused)]
         pub static $name_version: &[&str] = &[$($version),*];
     };
 }
 
 #[rustfmt::skip]
-declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[
+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 = "pre 1.29.0"]
@@ -44,11 +44,10 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[
     ("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<_>`"),
-    // end deprecated lints. used by `cargo dev deprecate_lint`
 ]}
 
 #[rustfmt::skip]
-declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
+declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
     #[clippy::version = ""]
@@ -187,5 +186,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
     ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
     #[clippy::version = ""]
     ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
-    // end renamed lints. used by `cargo dev rename_lint`
+    #[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"),
 ]}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 06528f875a2..3443b36eb4f 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -2,7 +2,7 @@ use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
-use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
+use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, paths};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, walk_item};
@@ -377,7 +377,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
     }
 
     if let Some(trait_def_id) = trait_ref.trait_def_id()
-        && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE)
+        && paths::SERDE_DESERIALIZE.matches(cx, trait_def_id)
         && let ty::Adt(def, _) = ty.kind()
         && let Some(local_def_id) = def.did().as_local()
         && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index fc6af204a74..9814d4fa84f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -3,6 +3,7 @@ use clippy_config::Conf;
 use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::macros::macro_backtrace;
+use clippy_utils::paths::PathNS;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
@@ -76,6 +77,7 @@ impl DisallowedMacros {
         let (disallowed, _) = create_disallowed_map(
             tcx,
             &conf.disallowed_macros,
+            PathNS::Macro,
             |def_kind| matches!(def_kind, DefKind::Macro(_)),
             "macro",
             false,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 1382dafa931..fb970e17f38 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,6 +1,7 @@
 use clippy_config::Conf;
 use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::PathNS;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
@@ -66,6 +67,7 @@ impl DisallowedMethods {
         let (disallowed, _) = create_disallowed_map(
             tcx,
             &conf.disallowed_methods,
+            PathNS::Value,
             |def_kind| {
                 matches!(
                     def_kind,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 2bae82648ac..d0b2f0c8407 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -1,6 +1,7 @@
 use clippy_config::Conf;
 use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::PathNS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
@@ -60,7 +61,14 @@ pub struct DisallowedTypes {
 
 impl DisallowedTypes {
     pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
-        let (def_ids, prim_tys) = create_disallowed_map(tcx, &conf.disallowed_types, def_kind_predicate, "type", true);
+        let (def_ids, prim_tys) = create_disallowed_map(
+            tcx,
+            &conf.disallowed_types,
+            PathNS::Type,
+            def_kind_predicate,
+            "type",
+            true,
+        );
         Self { def_ids, prim_tys }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index ab77edf1147..87da380e954 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -93,7 +93,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// //! <code>[first](x)second</code>
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.87.0"]
     pub DOC_LINK_CODE,
     nursery,
     "link with code back-to-back with other code"
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/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 3afb687040f..72f5eaf8a4b 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
     }
 }
 
+/// Check if the pattern has any type mismatch that would prevent it from being used in an equality
+/// check. This can happen if the expr has a reference type and the corresponding pattern is a
+/// literal.
+fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    let mut result = false;
+    pat.walk(|p| {
+        if result {
+            return false;
+        }
+
+        if p.span.in_external_macro(cx.sess().source_map()) {
+            return true;
+        }
+
+        let adjust_pat = match p.kind {
+            PatKind::Or([p, ..]) => p,
+            _ => p,
+        };
+
+        if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
+            && adjustments.first().is_some_and(|first| first.source.is_ref())
+        {
+            result = true;
+            return false;
+        }
+
+        true
+    });
+
+    result
+}
+
 impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Let(let_expr) = expr.kind
@@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
             let mut applicability = Applicability::MachineApplicable;
 
-            if is_structural_partial_eq(cx, exp_ty, pat_ty) {
+            if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) {
                 let pat_str = match let_expr.pat.kind {
                     PatKind::Struct(..) => format!(
                         "({})",
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 d5f0659f842..e653a57196d 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{
     eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate,
-    numeric_literal, peel_blocks, sugg,
+    numeric_literal, peel_blocks, sugg, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         rhs,
     ) = expr.kind
         && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind
-        && path.ident.name.as_str() == "exp"
+        && path.ident.name == sym::exp
         && cx.typeck_results().expr_ty(lhs).is_floating_point()
         && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
         && (F32(1.0) == value || F64(1.0) == value)
@@ -759,12 +759,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
             if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) {
-                match path.ident.name.as_str() {
-                    "ln" => check_ln1p(cx, expr, receiver),
-                    "log" => check_log_base(cx, expr, receiver, args),
-                    "powf" => check_powf(cx, expr, receiver, args),
-                    "powi" => check_powi(cx, expr, receiver, args),
-                    "sqrt" => check_hypot(cx, expr, receiver),
+                match path.ident.name {
+                    sym::ln => check_ln1p(cx, expr, receiver),
+                    sym::log => check_log_base(cx, expr, receiver, args),
+                    sym::powf => check_powf(cx, expr, receiver, args),
+                    sym::powi => check_powi(cx, expr, receiver, args),
+                    sym::sqrt => check_hypot(cx, expr, receiver),
                     _ => {},
                 }
             }
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/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index c8828c93615..5e2e2c9dbf7 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::path_def_id;
 use clippy_utils::ty::is_c_void;
+use clippy_utils::{path_def_id, sym};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,7 +40,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
-            && seg.ident.name.as_str() == "from_raw"
+            && seg.ident.name == sym::from_raw
             && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
             && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
             && let ty::RawPtr(ty, _) = arg_kind
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 25b087e8484..b816963cc82 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{is_in_const_context, is_integer_literal};
+use clippy_utils::{is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
 
             // check if the second part of the path indeed calls the associated
             // function `from_str_radix`
-            && pathseg.ident.name.as_str() == "from_str_radix"
+            && pathseg.ident.name == sym::from_str_radix
 
             // check if the first part of the path is some integer primitive
             && let TyKind::Path(ty_qpath) = &ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 5f3fc5100e7..d0d02a382d1 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -9,8 +9,8 @@ mod too_many_arguments;
 mod too_many_lines;
 
 use clippy_config::Conf;
-use clippy_utils::def_path_def_ids;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::paths::{PathNS, lookup_path_str};
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass};
@@ -469,7 +469,7 @@ impl Functions {
             trait_ids: conf
                 .allow_renamed_params_for
                 .iter()
-                .flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::<Vec<_>>()))
+                .flat_map(|p| lookup_path_str(tcx, PathNS::Type, p))
                 .collect(),
             msrv: conf.msrv,
         }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index d2545e57652..4c17834c3ad 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{Ty, TypeckResults};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
-use rustc_span::symbol::sym;
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 
 declare_clippy_lint! {
@@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         if let ExprKind::Call(fun, args) = e.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind
+            && matches!(method.ident.name, sym::new | sym::with_capacity)
             && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind
             && let Some(ty_did) = ty_path.res.opt_def_id()
         {
@@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                 return;
             }
 
-            if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
-                if method.ident.name == sym::new {
+            match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) {
+                (Some(sym::HashMap), sym::new) => {
                     self.suggestions.insert(e.span, "HashMap::default()".to_string());
-                } else if method.ident.name.as_str() == "with_capacity" {
+                },
+                (Some(sym::HashMap), sym::with_capacity) => {
                     self.suggestions.insert(
                         e.span,
                         format!(
@@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                             snippet(self.cx, args[0].span, "capacity"),
                         ),
                     );
-                }
-            } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
-                if method.ident.name == sym::new {
+                },
+                (Some(sym::HashSet), sym::new) => {
                     self.suggestions.insert(e.span, "HashSet::default()".to_string());
-                } else if method.ident.name.as_str() == "with_capacity" {
+                },
+                (Some(sym::HashSet), sym::with_capacity) => {
                     self.suggestions.insert(
                         e.span,
                         format!(
@@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
                             snippet(self.cx, args[0].span, "capacity"),
                         ),
                     );
-                }
+                },
+                _ => {},
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 514e72a4868..0823ef53ef9 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -69,7 +69,7 @@ declare_clippy_lint! {
     ///
     /// let result = a.saturating_sub(b);
     /// ```
-    #[clippy::version = "1.44.0"]
+    #[clippy::version = "1.83.0"]
     pub INVERTED_SATURATING_SUB,
     correctness,
     "Check if a variable is smaller than another one and still subtract from it even if smaller"
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/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 427a1f82555..c4e10837bf1 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::higher;
 use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
+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::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     .and(cap);
                 }
             }
-            if method.ident.name.as_str() == "flat_map"
+            if method.ident.name == sym::flat_map
                 && args.len() == 1
                 && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind
             {
@@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name.as_str() == "last" && args.is_empty() {
+            if method.ident.name == sym::last && args.is_empty() {
                 let not_double_ended = cx
                     .tcx
                     .get_diagnostic_item(sym::DoubleEndedIterator)
@@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 if not_double_ended {
                     return is_infinite(cx, receiver);
                 }
-            } else if method.ident.name.as_str() == "collect" {
+            } else if method.ident.name == sym::collect {
                 let ty = cx.typeck_results().expr_ty(expr);
                 if matches!(
                     get_type_diagnostic_name(cx, ty),
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index b1271a264b5..3d4dcd02070 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -5,7 +5,7 @@ use clippy_utils::macros::span_is_local;
 use clippy_utils::source::is_present_in_source;
 use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
+use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Symbol;
@@ -162,6 +162,7 @@ pub struct ItemNameRepetitions {
     enum_threshold: u64,
     struct_threshold: u64,
     avoid_breaking_exported_api: bool,
+    allow_exact_repetitions: bool,
     allow_private_module_inception: bool,
     allowed_prefixes: FxHashSet<String>,
 }
@@ -173,6 +174,7 @@ impl ItemNameRepetitions {
             enum_threshold: conf.enum_variant_name_threshold,
             struct_threshold: conf.struct_field_name_threshold,
             avoid_breaking_exported_api: conf.avoid_breaking_exported_api,
+            allow_exact_repetitions: conf.allow_exact_repetitions,
             allow_private_module_inception: conf.allow_private_module_inception,
             allowed_prefixes: conf.allowed_prefixes.iter().map(|s| to_camel_case(s)).collect(),
         }
@@ -405,6 +407,7 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>
     if count_match_start(item_name, name).char_count == item_name_chars
         && name.chars().nth(item_name_chars).is_some_and(|c| !c.is_lowercase())
         && name.chars().nth(item_name_chars + 1).is_some_and(|c| !c.is_numeric())
+        && !check_enum_tuple_path_match(name, variant.data)
     {
         span_lint_hir(
             cx,
@@ -420,7 +423,9 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>)
     let name = variant.ident.name.as_str();
     let item_name_chars = item_name.chars().count();
 
-    if count_match_end(item_name, name).char_count == item_name_chars {
+    if count_match_end(item_name, name).char_count == item_name_chars
+        && !check_enum_tuple_path_match(name, variant.data)
+    {
         span_lint_hir(
             cx,
             ENUM_VARIANT_NAMES,
@@ -431,6 +436,27 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>)
     }
 }
 
+/// Checks if an enum tuple variant contains a single field
+/// whose qualified path contains the variant's name.
+fn check_enum_tuple_path_match(variant_name: &str, variant_data: VariantData<'_>) -> bool {
+    // Only check single-field tuple variants
+    let VariantData::Tuple(fields, ..) = variant_data else {
+        return false;
+    };
+    if fields.len() != 1 {
+        return false;
+    }
+    // Check if field type is a path and contains the variant name
+    match fields[0].ty.kind {
+        TyKind::Path(QPath::Resolved(_, path)) => path
+            .segments
+            .iter()
+            .any(|segment| segment.ident.name.as_str() == variant_name),
+        TyKind::Path(QPath::TypeRelative(_, segment)) => segment.ident.name.as_str() == variant_name,
+        _ => false,
+    }
+}
+
 impl LateLintPass<'_> for ItemNameRepetitions {
     fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
         let Some(_ident) = item.kind.ident() else { return };
@@ -462,11 +488,21 @@ impl LateLintPass<'_> for ItemNameRepetitions {
             }
 
             // The `module_name_repetitions` lint should only trigger if the item has the module in its
-            // name. Having the same name is accepted.
-            if cx.tcx.visibility(item.owner_id).is_public()
-                && cx.tcx.visibility(mod_owner_id.def_id).is_public()
-                && item_camel.len() > mod_camel.len()
-            {
+            // name. Having the same name is only accepted if `allow_exact_repetition` is set to `true`.
+
+            let both_are_public =
+                cx.tcx.visibility(item.owner_id).is_public() && cx.tcx.visibility(mod_owner_id.def_id).is_public();
+
+            if both_are_public && !self.allow_exact_repetitions && item_camel == *mod_camel {
+                span_lint(
+                    cx,
+                    MODULE_NAME_REPETITIONS,
+                    ident.span,
+                    "item name is the same as its containing module's name",
+                );
+            }
+
+            if both_are_public && item_camel.len() > mod_camel.len() {
                 let matching = count_match_start(mod_camel, &item_camel);
                 let rmatching = count_match_end(mod_camel, &item_camel);
                 let nchars = mod_camel.chars().count();
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 173232c511a..900b20aa9cf 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_parent_as_impl;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection};
+use clippy_utils::{get_parent_as_impl, sym};
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -141,7 +140,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
                 ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some()
             })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
-                if item.ident.name.as_str() == "IntoIter" {
+                if item.ident.name == sym::IntoIter {
                     Some(cx.tcx.hir_impl_item(item.id).expect_type().span)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 8c71d34c95f..aded31971ce 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym};
+use clippy_utils::{
+    fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
+};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
 
     if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
-        if let Some(name) = get_item_name(cx, method)
-            && name.as_str() == "is_empty"
-        {
+        if parent_item_name(cx, method) == Some(sym::is_empty) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index bdbf5b37c5f..916191b2a7b 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
+use clippy_utils::ty::{implements_trait, is_must_use_ty};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{LetStmt, LocalSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -129,12 +129,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]);
 
-const SYNC_GUARD_PATHS: [&[&str]; 3] = [
-    &paths::PARKING_LOT_MUTEX_GUARD,
-    &paths::PARKING_LOT_RWLOCK_READ_GUARD,
-    &paths::PARKING_LOT_RWLOCK_WRITE_GUARD,
-];
-
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
@@ -144,7 +138,9 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
-                GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)),
+                GenericArgKind::Type(inner_ty) => inner_ty
+                    .ty_adt_def()
+                    .is_some_and(|adt| paths::PARKING_LOT_GUARDS.iter().any(|path| path.matches(cx, adt.did()))),
                 GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
             });
             if contains_sync_guard {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 9c8488ff381..1917ca24a05 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
+use rustc_errors::Applicability;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -32,13 +33,19 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
             && !local.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_from_proc_macro(cx, ty)
         {
-            span_lint_and_help(
+            span_lint_and_then(
                 cx,
                 LET_WITH_TYPE_UNDERSCORE,
                 local.span,
                 "variable declared with type underscore",
-                Some(ty.span.with_lo(local.pat.span.hi())),
-                "remove the explicit type `_` declaration",
+                |diag| {
+                    diag.span_suggestion_verbose(
+                        ty.span.with_lo(local.pat.span.hi()),
+                        "remove the explicit type `_` declaration",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 5fa8f6f4bf3..ff028713bf0 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(array_windows)]
-#![feature(binary_heap_into_iter_sorted)]
 #![feature(box_patterns)]
 #![feature(macro_metavar_expr_concat)]
 #![feature(f128)]
@@ -7,7 +6,6 @@
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iter_partition_in_place)]
-#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(round_char_boundary)]
 #![feature(rustc_private)]
@@ -37,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;
@@ -96,6 +94,7 @@ mod cargo;
 mod casts;
 mod cfg_not_test;
 mod checked_conversions;
+mod cloned_ref_to_slice_refs;
 mod cognitive_complexity;
 mod collapsible_if;
 mod collection_is_never_read;
@@ -729,8 +728,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
     store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
+    store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit));
     store.register_late_pass(|_| Box::new(returns::Return));
-    store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf)));
+    store.register_late_pass(move |_| Box::new(collapsible_if::CollapsibleIf::new(conf)));
     store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
     store.register_early_pass(|| Box::new(precedence::Precedence));
     store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
@@ -747,7 +747,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(conf)));
     store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
     store.register_late_pass(|_| Box::new(exit::Exit));
-    store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
+    store.register_late_pass(move |_| Box::new(to_digit_is_some::ToDigitIsSome::new(conf)));
     store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(conf)));
     store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(conf)));
     store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
@@ -943,5 +943,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
     store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
     store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
+    store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 5ef5e3a44f8..9a64226b1ed 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -88,7 +88,7 @@ declare_clippy_lint! {
     ///     x.chars()
     /// }
     /// ```
-    #[clippy::version = "1.84.0"]
+    #[clippy::version = "1.87.0"]
     pub ELIDABLE_LIFETIME_NAMES,
     pedantic,
     "lifetime name that can be replaced with the anonymous lifetime"
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
index 343f7c5d2d1..15c656cc7bc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{HasSession, snippet_with_applicability};
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{implements_trait, is_slice_like};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
 use rustc_ast::ast::LitKind;
@@ -58,6 +58,8 @@ pub(super) fn check<'tcx>(
         && let Res::Local(idx_hir) = idx_path.res
         && !is_local_used(cx, assignval, idx_hir)
         && msrv.meets(cx, msrvs::SLICE_FILL)
+        && let slice_ty = cx.typeck_results().expr_ty(slice).peel_refs()
+        && is_slice_like(cx, slice_ty)
     {
         sugg(cx, body, expr, slice.span, assignval.span);
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 2b66827e82e..56d2bef2305 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -778,7 +778,7 @@ declare_clippy_lint! {
     ///     let _ = s[idx..];
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.88.0"]
     pub CHAR_INDICES_AS_BYTE_INDICES,
     correctness,
     "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected"
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 661b4b590d8..388034c39f5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{msrvs, path_to_local, std_or_core};
+use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::SyntaxContext;
-use rustc_span::symbol::sym;
 
 /// Detects for loop pushing the same item into a Vec
 pub(super) fn check<'tcx>(
@@ -187,8 +186,8 @@ fn get_vec_push<'tcx>(
             // Extract method being called and figure out the parameters for the method call
             && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
             // Check that the method being called is push() on a Vec
+            && path.ident.name == sym::push
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
-            && path.ident.name.as_str() == "push"
     {
         return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index c515e41f242..bac4b3d32f2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -36,7 +36,7 @@ declare_clippy_lint! {
     /// a.abs_diff(b)
     /// # ;
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.88.0"]
     pub MANUAL_ABS_DIFF,
     complexity,
     "using an if-else pattern instead of `abs_diff`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index 444ecd5d2bb..ed0cce754b9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 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::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::{SpanlessEq, sym};
 use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
@@ -199,9 +199,9 @@ fn build_suggestion(
     } else {
         format!("{dividend_sugg_str}{type_suffix}")
     };
-    let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
+    let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
 
-    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
+    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
 
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index f71264a93ca..b3ee45cc020 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::visitors::{is_local_used, local_used_once};
-use clippy_utils::{is_trait_method, path_to_local_id};
+use clippy_utils::{is_trait_method, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -66,7 +65,7 @@ impl LateLintPass<'_> for ManualHashOne {
             && let Some(init) = local.init
             && !init.span.from_expansion()
             && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
-            && seg.ident.name.as_str() == "build_hasher"
+            && seg.ident.name == sym::build_hasher
 
             && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id)
             && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id)
@@ -94,7 +93,7 @@ impl LateLintPass<'_> for ManualHashOne {
             && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id)
             && !finish_expr.span.from_expansion()
             && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
-            && seg.ident.name.as_str() == "finish"
+            && seg.ident.name == sym::finish
 
             && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE)
         {
diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
index d92069edb6d..57c03fbb2ed 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -1,6 +1,7 @@
 use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
@@ -10,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::{Ty, UintTy};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,9 +48,9 @@ enum MatchType<'a, 'b> {
 
 fn get_ascii_type<'a, 'b>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'b>) -> Option<(Span, MatchType<'a, 'b>)> {
     if let MethodCall(path, expr, _, _) = kind {
-        let is_lower = match path.ident.name.as_str() {
-            "to_ascii_lowercase" => true,
-            "to_ascii_uppercase" => false,
+        let is_lower = match path.ident.name {
+            sym::to_ascii_lowercase => true,
+            sym::to_ascii_uppercase => false,
             _ => return None,
         };
         let ty_raw = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 8ab49bd2ea8..ac8c88f0205 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators};
+use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
@@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind,
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
                 check_is_ascii(cx, macro_call.span, recv, &range, None);
             }
         } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
-            && path.ident.name.as_str() == "contains"
+            && path.ident.name == sym::contains
             && let Some(higher::Range {
                 start: Some(start),
                 end: Some(end),
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index d6ac6e106b4..0b3bec714c0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -4,11 +4,14 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
+use clippy_utils::{
+    MaybePath, is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, path_res, peel_blocks,
+};
 use rustc_ast::BindingMode;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 
 use rustc_span::Span;
@@ -91,14 +94,15 @@ impl<'tcx> QuestionMark {
                     let Some((idx, diverging_arm)) = diverging_arm_opt else {
                         return;
                     };
+
+                    let pat_arm = &arms[1 - idx];
                     // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
                     // However, if it arrives in second position, its pattern may cover some cases already covered
                     // by the diverging one.
-                    // TODO: accept the non-diverging arm as a second position if patterns are disjointed.
-                    if idx == 0 {
+                    if idx == 0 && !is_arms_disjointed(cx, diverging_arm, pat_arm) {
                         return;
                     }
-                    let pat_arm = &arms[1 - idx];
+
                     let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else {
                         return;
                     };
@@ -110,6 +114,63 @@ impl<'tcx> QuestionMark {
     }
 }
 
+/// Checks if the patterns of the arms are disjointed. Currently, we only support patterns of simple
+/// enum variants without nested patterns or bindings.
+///
+/// TODO: Support more complex patterns.
+fn is_arms_disjointed(cx: &LateContext<'_>, arm1: &Arm<'_>, arm2: &Arm<'_>) -> bool {
+    if arm1.guard.is_some() || arm2.guard.is_some() {
+        return false;
+    }
+
+    if !is_enum_variant(cx, arm1.pat) || !is_enum_variant(cx, arm2.pat) {
+        return false;
+    }
+
+    true
+}
+
+/// Returns `true` if the given pattern is a variant of an enum.
+pub fn is_enum_variant(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    struct Pat<'hir>(&'hir rustc_hir::Pat<'hir>);
+
+    impl<'hir> MaybePath<'hir> for Pat<'hir> {
+        fn qpath_opt(&self) -> Option<&QPath<'hir>> {
+            match self.0.kind {
+                PatKind::Struct(ref qpath, fields, _)
+                    if fields
+                        .iter()
+                        .all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
+                {
+                    Some(qpath)
+                },
+                PatKind::TupleStruct(ref qpath, pats, _)
+                    if pats
+                        .iter()
+                        .all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
+                {
+                    Some(qpath)
+                },
+                PatKind::Expr(&PatExpr {
+                    kind: PatExprKind::Path(ref qpath),
+                    ..
+                }) => Some(qpath),
+                _ => None,
+            }
+        }
+
+        fn hir_id(&self) -> HirId {
+            self.0.hir_id
+        }
+    }
+
+    let res = path_res(cx, &Pat(pat));
+    matches!(
+        res,
+        Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
+    )
+}
+
 fn emit_manual_let_else(
     cx: &LateContext<'_>,
     span: Span,
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index e4ad3953b67..b55c11f2d5b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -1,14 +1,14 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs};
+use clippy_utils::{is_none_arm, msrvs, paths, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -76,30 +76,30 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
                 }
             },
             ExprKind::MethodCall(seg, callee, [], _) => {
-                if seg.ident.name.as_str() == "unwrap_or_default" {
+                if seg.ident.name == sym::unwrap_or_default {
                     check_map(cx, callee, span, self.msrv);
                 }
             },
-            ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() {
-                "unwrap_or" => {
+            ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name {
+                sym::unwrap_or => {
                     if is_empty_slice(cx, or) {
                         check_map(cx, callee, span, self.msrv);
                     }
                 },
-                "unwrap_or_else" => {
+                sym::unwrap_or_else => {
                     if returns_empty_slice(cx, or) {
                         check_map(cx, callee, span, self.msrv);
                     }
                 },
                 _ => {},
             },
-            ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() {
-                "map_or" => {
+            ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name {
+                sym::map_or => {
                     if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
                         check_as_ref(cx, callee, span, self.msrv);
                     }
                 },
-                "map_or_else" => {
+                sym::map_or_else => {
                     if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
                         check_as_ref(cx, callee, span, self.msrv);
                     }
@@ -220,5 +220,5 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    clippy_utils::is_expr_path_def_path(cx, expr, &["core", "slice", "raw", "from_ref"])
+    paths::SLICE_FROM_REF.matches_path(cx, expr)
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index b64ae0b24d8..3ac2c9fc2b3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -1,5 +1,6 @@
 use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline};
+use rustc_ast::{BindingMode, ByRef};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath};
@@ -16,7 +17,7 @@ use super::{MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT};
 
 fn get_some(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<HirId> {
     if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
-        && let PatKind::Binding(_, pat_id, _, _) = pat.kind
+        && let PatKind::Binding(BindingMode(ByRef::No, _), pat_id, _, _) = pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         // Since it comes from a pattern binding, we need to get the parent to actually match
         // against it.
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index a54d835b538..28efd2038b3 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -62,7 +62,7 @@ declare_clippy_lint! {
     /// let mut an_option = Some(0);
     /// let taken = an_option.replace(1);
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.87.0"]
     pub MEM_REPLACE_OPTION_WITH_SOME,
     style,
     "replacing an `Option` with `Some` instead of `replace()`"
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index d07870d4951..292fa08b598 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -21,8 +22,8 @@ pub(super) fn check<'tcx>(
 ) {
     if let ExprKind::MethodCall(path_segment, ..) = recv.kind
         && matches!(
-            path_segment.ident.name.as_str(),
-            "to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase"
+            path_segment.ident.name,
+            sym::to_lowercase | sym::to_uppercase | sym::to_ascii_lowercase | sym::to_ascii_uppercase
         )
     {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index e666f31217c..6d841853fbe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
-use clippy_utils::{is_mutable, is_trait_method, path_to_local};
+use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Instance;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use super::DOUBLE_ENDED_ITERATOR_LAST;
 
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
         && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
         // find the provided definition of Iterator::last
         && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
-        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last)
         // if the resolved method is the same as the provided definition
         && fn_def.def_id() == last_def.def_id
         && let self_ty = cx.typeck_results().expr_ty(self_expr)
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index da123f13d46..4dd54cf1974 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -233,12 +233,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
             // the latter only calls `effect` once
             let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
 
-            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" {
+            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some {
                 Some(Self::IsSome {
                     receiver,
                     side_effect_expr_span,
                 })
-            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" {
+            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok {
                 Some(Self::IsOk {
                     receiver,
                     side_effect_expr_span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
index bdc834bd47a..ec4b9c7ae2e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::{expr_or_init, paths};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
@@ -8,13 +9,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args
     if let [error_kind, error] = args
         && !expr.span.from_expansion()
         && !error_kind.span.from_expansion()
-        && clippy_utils::is_expr_path_def_path(cx, path, &clippy_utils::paths::IO_ERROR_NEW)
-        && clippy_utils::is_expr_path_def_path(
-            cx,
-            clippy_utils::expr_or_init(cx, error_kind),
-            &clippy_utils::paths::IO_ERRORKIND_OTHER,
-        )
         && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind
+        && paths::IO_ERROR_NEW.matches_path(cx, path)
+        && paths::IO_ERRORKIND_OTHER_CTOR.matches_path(cx, expr_or_init(cx, error_kind))
         && msrv.meets(cx, msrvs::IO_ERROR_OTHER)
     {
         span_lint_and_then(
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 0274e31b4c3..3fa83cd39d1 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
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::get_parent_expr;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition::Edition2021;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 use super::MANUAL_C_STR_LITERALS;
 
@@ -71,15 +71,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
         && cx.tcx.sess.edition() >= Edition2021
         && msrv.meets(cx, msrvs::C_STR_LITERALS)
     {
-        match fn_name.as_str() {
-            name @ ("from_bytes_with_nul" | "from_bytes_with_nul_unchecked")
+        match fn_name {
+            sym::from_bytes_with_nul | sym::from_bytes_with_nul_unchecked
                 if !arg.span.from_expansion()
                     && let ExprKind::Lit(lit) = arg.kind
                     && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node =>
             {
-                check_from_bytes(cx, expr, arg, name);
+                check_from_bytes(cx, expr, arg, fn_name);
             },
-            "from_ptr" => check_from_ptr(cx, expr, arg),
+            sym::from_ptr => check_from_ptr(cx, expr, arg),
             _ => {},
         }
     }
@@ -106,13 +106,13 @@ fn check_from_ptr(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) {
     }
 }
 /// Checks `CStr::from_bytes_with_nul(b"foo\0")`
-fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: &str) {
+fn check_from_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, method: Symbol) {
     let (span, applicability) = if let Some(parent) = get_parent_expr(cx, expr)
         && let ExprKind::MethodCall(method, ..) = parent.kind
         && [sym::unwrap, sym::expect].contains(&method.ident.name)
     {
         (parent.span, Applicability::MachineApplicable)
-    } else if method == "from_bytes_with_nul_unchecked" {
+    } else if method == sym::from_bytes_with_nul_unchecked {
         // `*_unchecked` returns `&CStr` directly, nothing needs to be changed
         (expr.span, Applicability::MachineApplicable)
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index 18978a1d2bc..e2df8ce1513 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{match_def_path, path_def_id};
+use clippy_utils::{path_res, sym};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
 
@@ -79,16 +80,15 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
     }
 
     let ty = cx.typeck_results().expr_ty(expr);
-    let ty_str = ty.to_string();
 
-    // `std::T::MAX` `std::T::MIN` constants
-    if let Some(id) = path_def_id(cx, expr) {
-        if match_def_path(cx, id, &["core", &ty_str, "MAX"]) {
-            return Some(MinMax::Max);
-        }
-
-        if match_def_path(cx, id, &["core", &ty_str, "MIN"]) {
-            return Some(MinMax::Min);
+    // `T::MAX` and `T::MIN` constants
+    if let hir::ExprKind::Path(hir::QPath::TypeRelative(base, seg)) = expr.kind
+        && let Res::PrimTy(_) = path_res(cx, base)
+    {
+        match seg.ident.name {
+            sym::MAX => return Some(MinMax::Max),
+            sym::MIN => return Some(MinMax::Min),
+            _ => {},
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index ad374dee516..e0e6a1a59b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4370,11 +4370,10 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    ///
-    /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
+    /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using
+    /// the `?` operator instead.
     ///
     /// ### Why is this bad?
-    ///
     /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
     /// This can be replaced with the `?` operator, which is more concise and idiomatic.
     ///
@@ -4429,7 +4428,7 @@ declare_clippy_lint! {
     /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap());
     /// file.bytes();
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.87.0"]
     pub UNBUFFERED_BYTES,
     perf,
     "calling .bytes() is very inefficient when data is not in memory"
@@ -4454,7 +4453,7 @@ declare_clippy_lint! {
     ///     values.contains(&10)
     /// }
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.87.0"]
     pub MANUAL_CONTAINS,
     perf,
     "unnecessary `iter().any()` on slices that can be replaced with `contains()`"
@@ -4710,6 +4709,8 @@ 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)> {
@@ -4908,6 +4909,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 impl Methods {
     #[allow(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // 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]) => {
@@ -5050,29 +5052,12 @@ impl Methods {
                         Some(("err", recv, [], err_span, _)) => {
                             err_expect::check(cx, expr, recv, span, err_span, self.msrv);
                         },
-                        _ => unwrap_expect_used::check(
-                            cx,
-                            expr,
-                            recv,
-                            false,
-                            self.allow_expect_in_consts,
-                            self.allow_expect_in_tests,
-                            unwrap_expect_used::Variant::Expect,
-                        ),
+                        _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("expect_err", [_]) => {
+                ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        true,
-                        self.allow_expect_in_consts,
-                        self.allow_expect_in_tests,
-                        unwrap_expect_used::Variant::Expect,
-                    );
                 },
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
@@ -5438,27 +5423,6 @@ impl Methods {
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        false,
-                        self.allow_unwrap_in_consts,
-                        self.allow_unwrap_in_tests,
-                        unwrap_expect_used::Variant::Unwrap,
-                    );
-                },
-                ("unwrap_err", []) => {
-                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_expect_used::check(
-                        cx,
-                        expr,
-                        recv,
-                        true,
-                        self.allow_unwrap_in_consts,
-                        self.allow_unwrap_in_tests,
-                        unwrap_expect_used::Variant::Unwrap,
-                    );
                 },
                 ("unwrap_or", [u_arg]) => {
                     match method_call(recv) {
@@ -5487,9 +5451,6 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_unchecked" | "unwrap_err_unchecked", []) => {
-                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                },
                 ("unwrap_or_else", [u_arg]) => {
                     match method_call(recv) {
                         Some(("map", recv, [map_arg], _, _))
@@ -5527,6 +5488,56 @@ 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", _, [], _, _))) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_expect_in_consts,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
+                },
+                ("expect_err", [_]) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_expect_in_consts,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
+                },
+                ("unwrap", []) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_unwrap_in_consts,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
+                },
+                ("unwrap_err", []) => {
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_unwrap_in_consts,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
+                },
+                _ => {},
+            }
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 743aacf0588..71c1576cd57 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -7,9 +7,8 @@ use rustc_span::Span;
 use super::NEEDLESS_CHARACTER_ITERATION;
 use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::paths::CHAR_IS_ASCII;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
+use clippy_utils::{is_path_diagnostic_item, path_to_local_id, peel_blocks, sym};
 
 fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
     while let ExprKind::AddrOf(_, _, e) = expr.kind {
@@ -32,7 +31,7 @@ fn handle_expr(
             // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
             // `is_ascii`, then only `.all()` should warn.
             if revert != is_all
-                && method.ident.name.as_str() == "is_ascii"
+                && method.ident.name == sym::is_ascii
                 && path_to_local_id(receiver, first_param)
                 && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
                 && *char_arg_ty.kind() == ty::Char
@@ -76,9 +75,7 @@ fn handle_expr(
             // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
             // `is_ascii`, then only `.all()` should warn.
             if revert != is_all
-                && let ExprKind::Path(path) = fn_path.kind
-                && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
-                && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII)
+                && is_path_diagnostic_item(cx, fn_path, sym::char_is_ascii)
                 && path_to_local_id(peels_expr_ref(arg), first_param)
                 && let Some(snippet) = before_chars.get_source_text(cx)
             {
@@ -102,7 +99,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
         && let body = cx.tcx.hir_body(body)
         && let Some(first_param) = body.params.first()
         && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind
-        && method.ident.name.as_str() == "chars"
+        && method.ident.name == sym::chars
         && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs()
         && *str_ty.kind() == ty::Str
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 6efaba525e3..4c1ed6a1d83 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -9,7 +9,7 @@ use clippy_utils::ty::{
 };
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local,
-    path_to_local_id,
+    path_to_local_id, sym,
 };
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
@@ -20,8 +20,8 @@ use rustc_hir::{
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_span::Span;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, sym};
 
 const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
 
@@ -339,7 +339,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
         // Check function calls on our collection
         if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
             if args.is_empty()
-                && method_name.ident.name.as_str() == "collect"
+                && method_name.ident.name == sym::collect
                 && is_trait_method(self.cx, expr, sym::Iterator)
             {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
@@ -357,20 +357,20 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
                     if let Some(hir_id) = self.current_statement_hir_id {
                         self.hir_id_uses_map.insert(hir_id, self.uses.len());
                     }
-                    match method_name.ident.name.as_str() {
-                        "into_iter" => self.uses.push(Some(IterFunction {
+                    match method_name.ident.name {
+                        sym::into_iter => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::IntoIter(expr.hir_id),
                             span: expr.span,
                         })),
-                        "len" => self.uses.push(Some(IterFunction {
+                        sym::len => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::Len,
                             span: expr.span,
                         })),
-                        "is_empty" => self.uses.push(Some(IterFunction {
+                        sym::is_empty => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::IsEmpty,
                             span: expr.span,
                         })),
-                        "contains" => self.uses.push(Some(IterFunction {
+                        sym::contains => self.uses.push(Some(IterFunction {
                             func: IterFunctionKind::Contains(args[0].span),
                             span: expr.span,
                         })),
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index da084871402..bce314e64f0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxHashMap;
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
-use clippy_utils::{match_any_def_paths, paths};
+use clippy_utils::paths;
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -13,7 +13,7 @@ use rustc_span::{Span, sym};
 use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS};
 
 fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || match_type(cx, ty, &paths::TOKIO_IO_OPEN_OPTIONS)
+    is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || paths::TOKIO_IO_OPEN_OPTIONS.matches_ty(cx, ty)
 }
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
@@ -126,14 +126,14 @@ fn get_open_options(
         && let ExprKind::Path(path) = callee.kind
         && let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id()
     {
-        let std_file_options = [sym::file_options, sym::open_options_new];
-
-        let tokio_file_options: &[&[&str]] = &[&paths::TOKIO_IO_OPEN_OPTIONS_NEW, &paths::TOKIO_FILE_OPTIONS];
+        let is_std_options = matches!(
+            cx.tcx.get_diagnostic_name(did),
+            Some(sym::file_options | sym::open_options_new)
+        );
 
-        let is_std_options = std_file_options
-            .into_iter()
-            .any(|sym| cx.tcx.is_diagnostic_item(sym, did));
-        is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some()
+        is_std_options
+            || paths::TOKIO_IO_OPEN_OPTIONS_NEW.matches(cx, did)
+            || paths::TOKIO_FILE_OPTIONS.matches(cx, did)
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index fe999a3b5f8..407f2e80aff 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,17 +1,16 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
 
 use super::READ_LINE_WITHOUT_TRIM;
 
@@ -44,7 +43,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
             if let Some(parent) = get_parent_expr(cx, expr) {
                 let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind {
                     if args.is_empty()
-                        && segment.ident.name.as_str() == "parse"
+                        && segment.ident.name == sym::parse
                         && let parse_result_ty = cx.typeck_results().expr_ty(parent)
                         && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
                         && let ty::Adt(_, substs) = parse_result_ty.kind()
@@ -58,7 +57,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                             "calling `.parse()` on a string without trimming the trailing newline character",
                             "checking",
                         ))
-                    } else if segment.ident.name.as_str() == "ends_with"
+                    } else if segment.ident.name == sym::ends_with
                         && recv.span == expr.span
                         && let [arg] = args
                         && expr_is_string_literal_without_trailing_newline(arg)
diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
index e8861935d42..df8544f9220 100644
--- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
@@ -9,7 +9,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
 use clippy_utils::ty::get_type_diagnostic_name;
 use clippy_utils::visitors::for_each_unconsumed_temporary;
-use clippy_utils::{is_expr_final_block_expr, peel_blocks};
+use clippy_utils::{get_parent_expr, peel_blocks};
 
 use super::RETURN_AND_THEN;
 
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx hir::Expr<'tcx>,
     arg: &'tcx hir::Expr<'_>,
 ) {
-    if !is_expr_final_block_expr(cx.tcx, expr) {
+    if cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_none() {
         return;
     }
 
@@ -55,13 +55,32 @@ pub(super) fn check<'tcx>(
         None => &body_snip,
     };
 
-    let msg = "use the question mark operator instead of an `and_then` call";
-    let sugg = format!(
-        "let {} = {}?;\n{}",
-        arg_snip,
-        recv_snip,
-        reindent_multiline(inner, false, indent_of(cx, expr.span))
-    );
+    // If suggestion is going to get inserted as part of a `return` expression, it must be blockified.
+    let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
+        let base_indent = indent_of(cx, parent_expr.span);
+        let inner_indent = base_indent.map(|i| i + 4);
+        format!(
+            "{}\n{}\n{}",
+            reindent_multiline(&format!("{{\nlet {arg_snip} = {recv_snip}?;"), true, inner_indent),
+            reindent_multiline(inner, false, inner_indent),
+            reindent_multiline("}", false, base_indent),
+        )
+    } else {
+        format!(
+            "let {} = {}?;\n{}",
+            arg_snip,
+            recv_snip,
+            reindent_multiline(inner, false, indent_of(cx, expr.span))
+        )
+    };
 
-    span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
+    span_lint_and_sugg(
+        cx,
+        RETURN_AND_THEN,
+        expr.span,
+        "use the `?` operator instead of an `and_then` call",
+        "try",
+        sugg,
+        applicability,
+    );
 }
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 3586e11f56a..fb4ac7b3613 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::sym;
 use clippy_utils::visitors::is_const_evaluatable;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
         && !is_const_evaluatable(cx, trim_recv)
         && let ExprKind::Lit(split_lit) = split_arg.kind
         && (matches!(split_lit.node, LitKind::Char('\n'))
-            || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n")))
+            || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _)))
     {
         let mut app = Applicability::MaybeIncorrect;
         span_lint_and_sugg(
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 d183457da25..c8efb600f57 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, match_def_path, path_to_local_id, paths};
+use clippy_utils::{is_diag_item_method, path_to_local_id, paths};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
@@ -288,7 +288,7 @@ fn parse_iter_usage<'tcx>(
             match (name.ident.as_str(), args) {
                 ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
                 ("next_tuple", []) => {
-                    return if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE)
+                    return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did)
                         && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind()
                         && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did())
                         && let ty::Tuple(subs) = subs.type_at(0).kind()
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 f920f306bc1..79ed352193f 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
@@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_copy;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
+use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::sym;
 
 use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
 
@@ -95,7 +94,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             (true, true)
         },
         hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
-            if segment.ident.name.as_str() == "then_some"
+            if segment.ident.name == sym::then_some
                 && cx.typeck_results().expr_ty(recv).is_bool()
                 && path_to_local_id(arg, arg_id)
             {
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 206b0a8ae3c..87bb8d46a1d 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
@@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{
     fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs,
-    return_ty,
+    return_ty, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{
     self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
 };
-use rustc_span::{Symbol, sym};
+use rustc_span::Symbol;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
 
@@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>,
 /// call of a `to_owned`-like function is unnecessary.
 fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if let Some(parent) = get_parent_expr(cx, expr)
-        && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent)
-        && fn_name.as_str() == "split"
+        && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent)
         && let Some(receiver_snippet) = receiver.span.get_source_text(cx)
         && let Some(arg_snippet) = argument_expr.span.get_source_text(cx)
     {
@@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool {
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
 fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    (method_name.as_str() == "cloned" || method_name.as_str() == "copied")
-        && is_diag_trait_item(cx, method_def_id, sym::Iterator)
+    matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator)
 }
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
@@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name:
 
 /// Returns true if the named method is `Cow::into_owned`.
 fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
+    method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow)
 }
 
 /// Returns true if the named method is `ToString::to_string` and it's called on a type that
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 0cbf6004be3..17e2620d9dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,9 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, should_call_clone_as_function, walk_ptrs_ty_depth};
-use clippy_utils::{
-    get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, peel_blocks, strip_pat_refs,
-};
+use clippy_utils::{get_parent_expr, is_diag_trait_item, path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
@@ -81,8 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
                 applicability,
             );
         }
-    } else if match_def_path(cx, def_id, &["core", "option", "Option", call_name])
-        || match_def_path(cx, def_id, &["core", "result", "Result", call_name])
+    } else if let Some(impl_id) = cx.tcx.opt_parent(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()))
     {
         let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs();
         let res_ty = cx.typeck_results().expr_ty(expr).peel_refs();
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index ed89b3b3438..64eafc0ebcc 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,10 +1,9 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_trait_method;
+use clippy_utils::{is_trait_method, sym};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::cmp::Ordering::{Equal, Greater, Less};
 
 declare_clippy_lint! {
@@ -79,12 +78,10 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM
         },
         ExprKind::MethodCall(path, receiver, args @ [_], _) => {
             if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
-                if path.ident.name.as_str() == "max" {
-                    fetch_const(cx, Some(receiver), args, MinMax::Max)
-                } else if path.ident.name.as_str() == "min" {
-                    fetch_const(cx, Some(receiver), args, MinMax::Min)
-                } else {
-                    None
+                match path.ident.name {
+                    sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max),
+                    sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min),
+                    _ => None,
                 }
             } else {
                 None
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 1f142bc3ba6..f3e24044fb6 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
@@ -155,9 +155,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        let mir = cx.tcx.mir_drops_elaborated_and_const_checked(def_id);
+        let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Ok(()) = is_min_const_fn(cx, &mir.borrow(), self.msrv)
+        if let Ok(()) = is_min_const_fn(cx, mir, self.msrv)
             && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) =
                 cx.tcx.hir_node_by_def_id(def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index b234b190153..7772051eb5c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -48,6 +48,8 @@ pub struct MissingDoc {
     /// Whether to **only** check for missing documentation in items visible within the current
     /// crate. For example, `pub(crate)` items.
     crate_items_only: bool,
+    /// Whether to allow fields starting with an underscore to skip documentation requirements
+    allow_unused: bool,
     /// Stack of whether #[doc(hidden)] is set
     /// at each level which has lint attributes.
     doc_hidden_stack: Vec<bool>,
@@ -59,6 +61,7 @@ impl MissingDoc {
     pub fn new(conf: &'static Conf) -> Self {
         Self {
             crate_items_only: conf.missing_docs_in_crate_items,
+            allow_unused: conf.missing_docs_allow_unused,
             doc_hidden_stack: vec![false],
             prev_span: None,
         }
@@ -260,11 +263,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
-        if !sf.is_positional() {
+        if !(sf.is_positional()
+            || is_from_proc_macro(cx, sf)
+            || self.allow_unused && sf.ident.as_str().starts_with('_'))
+        {
             let attrs = cx.tcx.hir_attrs(sf.hir_id);
-            if !is_from_proc_macro(cx, sf) {
-                self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
-            }
+            self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
         }
         self.prev_span = Some(sf.span);
     }
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 66631a69206..a1e621cc9f6 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -1,6 +1,6 @@
 use clippy_config::Conf;
-use clippy_utils::def_path_def_ids;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::{PathNS, lookup_path_str};
 use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -56,8 +56,12 @@ impl ImportRename {
             renames: conf
                 .enforced_import_renames
                 .iter()
-                .map(|x| (x.path.split("::").collect::<Vec<_>>(), Symbol::intern(&x.rename)))
-                .flat_map(|(path, rename)| def_path_def_ids(tcx, &path).map(move |id| (id, rename)))
+                .map(|x| (&x.path, Symbol::intern(&x.rename)))
+                .flat_map(|(path, rename)| {
+                    lookup_path_str(tcx, PathNS::Arbitrary, path)
+                        .into_iter()
+                        .map(move |id| (id, rename))
+                })
                 .collect(),
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 1932d2d5f97..be7dd74fd62 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_path_lang_item;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Visitable, for_each_expr};
+use clippy_utils::{is_path_lang_item, sym};
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
@@ -13,7 +13,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{Ty, TypeckResults};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -116,7 +116,7 @@ fn should_lint<'tcx>(
 
             if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
                 has_debug_struct = true;
-            } else if path.ident.name.as_str() == "finish_non_exhaustive"
+            } else if path.ident.name == sym::finish_non_exhaustive
                 && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
             {
                 has_finish_non_exhaustive = true;
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 0e085585962..d9f4fb271fb 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
+use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym};
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> {
 
     fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(self.cx, e)
-            && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo"
+            && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 270eebe0758..3b271ca0dc1 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::sym;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
@@ -42,10 +43,9 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
         let Some(macro_call) = root_macro_call_first_node(cx, e) else {
             return;
         };
-        let macro_name = cx.tcx.item_name(macro_call.def_id);
         if !matches!(
-            macro_name.as_str(),
-            "debug_assert" | "debug_assert_eq" | "debug_assert_ne"
+            cx.tcx.get_diagnostic_name(macro_call.def_id),
+            Some(sym::debug_assert_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro)
         ) {
             return;
         }
@@ -60,7 +60,10 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
                     cx,
                     DEBUG_ASSERT_WITH_MUT_CALL,
                     span,
-                    format!("do not call a function with mutable arguments inside of `{macro_name}!`"),
+                    format!(
+                        "do not call a function with mutable arguments inside of `{}!`",
+                        cx.tcx.item_name(macro_call.def_id)
+                    ),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 90b27f5dbac..7dd96f1f037 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::has_iter_method;
+use clippy_utils::{is_trait_method, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
                 iter_recv.kind,
                 ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
             )
-            && method_name.ident.name.as_str() == "for_each"
+            && method_name.ident.name == sym::for_each
             && is_trait_method(cx, expr, sym::Iterator)
             // Checks the type of the `iter` method receiver is NOT a user defined type.
             && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 72b0a80260e..2a2160c3be2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,6 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::path_res;
-use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
@@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Suggests alternatives for useless applications of `?` in terminating expressions
+    /// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator
+    /// is not needed to convert the type of `x`.
     ///
     /// ### Why is this bad?
     /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
     ///
     /// ### Example
     /// ```no_run
-    /// struct TO {
-    ///     magic: Option<usize>,
+    /// # use std::num::ParseIntError;
+    /// fn f(s: &str) -> Option<usize> {
+    ///     Some(s.find('x')?)
     /// }
     ///
-    /// fn f(to: TO) -> Option<usize> {
-    ///     Some(to.magic?)
+    /// fn g(s: &str) -> Result<usize, ParseIntError> {
+    ///     Ok(s.parse()?)
     /// }
-    ///
-    /// struct TR {
-    ///     magic: Result<usize, bool>,
-    /// }
-    ///
-    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
-    ///     tr.and_then(|t| Ok(t.magic?))
-    /// }
-    ///
     /// ```
     /// Use instead:
     /// ```no_run
-    /// struct TO {
-    ///     magic: Option<usize>,
+    /// # use std::num::ParseIntError;
+    /// fn f(s: &str) -> Option<usize> {
+    ///     s.find('x')
     /// }
     ///
-    /// fn f(to: TO) -> Option<usize> {
-    ///     to.magic
-    /// }
-    ///
-    /// struct TR {
-    ///     magic: Result<usize, bool>,
-    /// }
-    ///
-    /// fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
-    ///     tr.and_then(|t| t.magic)
+    /// fn g(s: &str) -> Result<usize, ParseIntError> {
+    ///     s.parse()
     /// }
     /// ```
     #[clippy::version = "1.51.0"]
     pub NEEDLESS_QUESTION_MARK,
     complexity,
-    "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
+    "using `Ok(x?)` or `Some(x?)` where `x` would be equivalent"
 }
 
 declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
@@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::Call(path, [arg]) = expr.kind
         && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path)
         && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
-        && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
-            "Some()"
+        && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
+            "Some"
         } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) {
-            "Ok()"
+            "Ok"
         } else {
             return;
         }
@@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
         && let inner_ty = cx.typeck_results().expr_ty(inner_expr)
         && expr_ty == inner_ty
     {
-        span_lint_and_sugg(
+        span_lint_hir_and_then(
             cx,
             NEEDLESS_QUESTION_MARK,
+            expr.hir_id,
             expr.span,
-            "question mark operator is useless here",
-            format!("try removing question mark and `{sugg_remove}`"),
-            format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
-            Applicability::MachineApplicable,
+            format!("enclosing `{variant}` and `?` operator are unneeded"),
+            |diag| {
+                diag.multipart_suggestion(
+                    format!("remove the enclosing `{variant}` and `?` operator"),
+                    vec![
+                        (expr.span.until(inner_expr.span), String::new()),
+                        (
+                            inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                            String::new(),
+                        ),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
         );
     }
 }
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 63859c0396e..6d3e77b6b6e 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -263,7 +263,7 @@ impl<'tcx> NonCopyConst<'tcx> {
     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(def_id, args);
+        let instance = ty::Instance::new_raw(def_id, args);
         let cid = GlobalId {
             instance,
             promoted: None,
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 852c3885f56..23a1622f30f 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{SpanRangeExt, snippet_with_applicability};
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
         match &expr.kind {
             ExprKind::MethodCall(path, func, [param], _) => {
                 if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def()
-                    && ((path.ident.name.as_str() == "mode"
+                    && ((path.ident.name == sym::mode
                         && matches!(
                             cx.tcx.get_diagnostic_name(adt.did()),
                             Some(sym::FsOpenOptions | sym::DirBuilder)
                         ))
-                        || (path.ident.name.as_str() == "set_mode"
+                        || (path.ident.name == sym::set_mode
                             && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index f6bc9428d65..f66b9519317 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -1,13 +1,14 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::paths::{self, PathNS, find_crates, lookup_path_str};
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{def_path_def_ids, fn_def_id, is_no_std_crate, path_def_id};
+use clippy_utils::{fn_def_id, is_no_std_crate, path_def_id, sym};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind};
+use rustc_hir::{self as hir, BodyId, Expr, ExprKind, HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -62,10 +63,7 @@ static FUNCTION_REPLACEMENTS: &[(&str, Option<&str>)] = &[
 
 pub struct NonStdLazyStatic {
     msrv: Msrv,
-    lazy_static_lazy_static: Vec<DefId>,
-    once_cell_crate: Vec<CrateNum>,
-    once_cell_sync_lazy: Vec<DefId>,
-    once_cell_sync_lazy_new: Vec<DefId>,
+    once_cell_crates: Vec<CrateNum>,
     sugg_map: FxIndexMap<DefId, Option<String>>,
     lazy_type_defs: FxIndexMap<DefId, LazyInfo>,
     uses_other_once_cell_types: bool,
@@ -76,10 +74,7 @@ impl NonStdLazyStatic {
     pub fn new(conf: &'static Conf) -> Self {
         Self {
             msrv: conf.msrv,
-            lazy_static_lazy_static: Vec::new(),
-            once_cell_crate: Vec::new(),
-            once_cell_sync_lazy: Vec::new(),
-            once_cell_sync_lazy_new: Vec::new(),
+            once_cell_crates: Vec::new(),
             sugg_map: FxIndexMap::default(),
             lazy_type_defs: FxIndexMap::default(),
             uses_other_once_cell_types: false,
@@ -95,17 +90,15 @@ fn can_use_lazy_cell(cx: &LateContext<'_>, msrv: Msrv) -> bool {
 
 impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
     fn check_crate(&mut self, cx: &LateContext<'hir>) {
-        // Fetch def_ids for external paths
-        self.lazy_static_lazy_static = def_path_def_ids(cx.tcx, &["lazy_static", "lazy_static"]).collect();
-        self.once_cell_sync_lazy = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy"]).collect();
-        self.once_cell_sync_lazy_new = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy", "new"]).collect();
-        // And CrateNums for `once_cell` crate
-        self.once_cell_crate = self.once_cell_sync_lazy.iter().map(|d| d.krate).collect();
+        // Add CrateNums for `once_cell` crate
+        self.once_cell_crates = find_crates(cx.tcx, sym::once_cell)
+            .iter()
+            .map(|def_id| def_id.krate)
+            .collect();
 
         // Convert hardcoded fn replacement list into a map with def_id
         for (path, sugg) in FUNCTION_REPLACEMENTS {
-            let path_vec: Vec<&str> = path.split("::").collect();
-            for did in def_path_def_ids(cx.tcx, &path_vec) {
+            for did in lookup_path_str(cx.tcx, PathNS::Value, path) {
                 self.sugg_map.insert(did, sugg.map(ToOwned::to_owned));
             }
         }
@@ -114,7 +107,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
     fn check_item(&mut self, cx: &LateContext<'hir>, item: &Item<'hir>) {
         if let ItemKind::Static(..) = item.kind
             && let Some(macro_call) = clippy_utils::macros::root_macro_call(item.span)
-            && self.lazy_static_lazy_static.contains(&macro_call.def_id)
+            && paths::LAZY_STATIC.matches(cx, macro_call.def_id)
             && can_use_lazy_cell(cx, self.msrv)
         {
             span_lint(
@@ -130,7 +123,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
             return;
         }
 
-        if let Some(lazy_info) = LazyInfo::from_item(self, cx, item)
+        if let Some(lazy_info) = LazyInfo::from_item(cx, item)
             && can_use_lazy_cell(cx, self.msrv)
         {
             self.lazy_type_defs.insert(item.owner_id.to_def_id(), lazy_info);
@@ -155,9 +148,9 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
         if let rustc_hir::TyKind::Path(qpath) = ty.peel_refs().kind
             && let Some(ty_def_id) = cx.qpath_res(&qpath, ty.hir_id).opt_def_id()
             // Is from `once_cell` crate
-            && self.once_cell_crate.contains(&ty_def_id.krate)
+            && self.once_cell_crates.contains(&ty_def_id.krate)
             // And is NOT `once_cell::sync::Lazy`
-            && !self.once_cell_sync_lazy.contains(&ty_def_id)
+            && !paths::ONCE_CELL_SYNC_LAZY.matches(cx, ty_def_id)
         {
             self.uses_other_once_cell_types = true;
         }
@@ -180,6 +173,8 @@ struct LazyInfo {
     /// //          ^^^^
     /// ```
     ty_span_no_args: Span,
+    /// Item on which the lint must be generated.
+    item_hir_id: HirId,
     /// `Span` and `DefId` of calls on `Lazy` type.
     /// i.e.:
     /// ```ignore
@@ -190,12 +185,12 @@ struct LazyInfo {
 }
 
 impl LazyInfo {
-    fn from_item(state: &NonStdLazyStatic, cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
+    fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
         // Check if item is a `once_cell:sync::Lazy` static.
         if let ItemKind::Static(_, ty, _, body_id) = item.kind
             && let Some(path_def_id) = path_def_id(cx, ty)
             && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
-            && state.once_cell_sync_lazy.contains(&path_def_id)
+            && paths::ONCE_CELL_SYNC_LAZY.matches(cx, path_def_id)
         {
             let ty_span_no_args = path_span_without_args(path);
             let body = cx.tcx.hir_body(body_id);
@@ -204,7 +199,7 @@ impl LazyInfo {
             let mut new_fn_calls = FxIndexMap::default();
             for_each_expr::<(), ()>(cx, body, |ex| {
                 if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id)
-                    && state.once_cell_sync_lazy_new.contains(&fn_did)
+                    && paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did)
                 {
                     new_fn_calls.insert(call_span, fn_did);
                 }
@@ -213,6 +208,7 @@ impl LazyInfo {
 
             Some(LazyInfo {
                 ty_span_no_args,
+                item_hir_id: item.hir_id(),
                 calls_span_and_id: new_fn_calls,
             })
         } else {
@@ -236,9 +232,10 @@ impl LazyInfo {
             }
         }
 
-        span_lint_and_then(
+        span_lint_hir_and_then(
             cx,
             NON_STD_LAZY_STATICS,
+            self.item_hir_id,
             self.ty_span_no_args,
             "this type has been superseded by `LazyLock` in the standard library",
             |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
index 635f5678e2a..1b8ab1bdedf 100644
--- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
+use clippy_utils::sym;
 use rustc_ast::ast::BinOpKind;
 use rustc_errors::Applicability;
 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::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit
         && let ExprKind::Path(qpath) = &func.kind
         && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
         && let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind
-        && rcv_path.ident.name.as_str() == "get"
+        && rcv_path.ident.name == sym::get
     {
         let fn_name = cx.tcx.item_name(def_id);
         let target_ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index 1421893274f..d79101a687d 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -1,20 +1,18 @@
 use clippy_utils::ast_utils::is_useless_with_eq_exprs;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
-use clippy_utils::{eq_expr_value, is_in_test_function};
+use clippy_utils::{eq_expr_value, is_in_test_function, sym};
 use rustc_hir::{BinOpKind, Expr};
 use rustc_lint::LateContext;
 
 use super::EQ_OP;
 
 pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-    if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
-        let name = cx.tcx.item_name(macro_call.def_id);
+    if let Some(macro_call) = first_node_macro_backtrace(cx, e).find(|macro_call| {
         matches!(
-            name.as_str(),
-            "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne"
+            cx.tcx.get_diagnostic_name(macro_call.def_id),
+            Some(sym::assert_eq_macro | sym::assert_ne_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro)
         )
-        .then(|| (macro_call, name))
     }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn)
         && eq_expr_value(cx, lhs, rhs)
         && macro_call.is_local()
@@ -24,7 +22,10 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             cx,
             EQ_OP,
             lhs.span.to(rhs.span),
-            format!("identical args used in this `{macro_name}!` macro call"),
+            format!(
+                "identical args used in this `{}!` macro call",
+                cx.tcx.item_name(macro_call.def_id)
+            ),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 01dc6a27c33..ded161c8576 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::get_item_name;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{parent_item_name, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
@@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>(
             return;
         }
 
-        if let Some(name) = get_item_name(cx, expr) {
+        if let Some(name) = parent_item_name(cx, expr) {
             let name = name.as_str();
             if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") {
                 return;
@@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 
     if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind
-        && method_name.ident.name.as_str() == "signum"
+        && method_name.ident.name == sym::signum
     // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
     // the method call)
     {
diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
index 76eba7327cf..7b98afa9b40 100644
--- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
@@ -1,6 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
 
 use super::INTEGER_DIVISION;
 
@@ -13,7 +15,8 @@ pub(crate) fn check<'tcx>(
 ) {
     if op == hir::BinOpKind::Div
         && cx.typeck_results().expr_ty(left).is_integral()
-        && cx.typeck_results().expr_ty(right).is_integral()
+        && let right_ty = cx.typeck_results().expr_ty(right)
+        && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero))
     {
         #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index eebc62e2a5a..ee1d59490ce 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use clippy_utils::{is_inside_always_const_context, return_ty};
@@ -69,10 +69,11 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
             return ControlFlow::Continue(Descend::Yes);
         };
         if !is_inside_always_const_context(cx.tcx, e.hir_id)
-            && matches!(
-                cx.tcx.item_name(macro_call.def_id).as_str(),
-                "panic" | "assert" | "assert_eq" | "assert_ne"
-            )
+            && (is_panic(cx, macro_call.def_id)
+                || matches!(
+                    cx.tcx.get_diagnostic_name(macro_call.def_id),
+                    Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro)
+                ))
         {
             panics.push(macro_call.span);
             ControlFlow::Continue(Descend::No)
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index 39ae9967e01..8962f36db1e 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -113,8 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                 );
                 return;
             }
-            match cx.tcx.item_name(macro_call.def_id).as_str() {
-                "todo" => {
+            match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+                Some(sym::todo_macro) => {
                     span_lint(
                         cx,
                         TODO,
@@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                         "`todo` should not be present in production code",
                     );
                 },
-                "unimplemented" => {
+                Some(sym::unimplemented_macro) => {
                     span_lint(
                         cx,
                         UNIMPLEMENTED,
@@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                         "`unimplemented` should not be present in production code",
                     );
                 },
-                "unreachable" => {
+                Some(sym::unreachable_macro) => {
                     span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
                 },
                 _ => {},
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
index dc142b6e157..da56a785007 100644
--- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
         if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
             && let ExprKind::Lit(lit) = &arg.kind
             && LitKind::Bool(false) == lit.node
-            && path.ident.name.as_str() == "set_readonly"
+            && path.ident.name == sym::set_readonly
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 491961408ad..9149406642d 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -743,9 +743,9 @@ fn check_ptr_eq<'tcx>(
     }
 
     // Remove one level of usize conversion if any
-    let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
-        (Some(lhs), Some(rhs)) => (lhs, rhs),
-        _ => (left, right),
+    let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
+        (Some(lhs), Some(rhs)) => (lhs, rhs, true),
+        _ => (left, right, false),
     };
 
     // This lint concerns raw pointers
@@ -754,7 +754,12 @@ fn check_ptr_eq<'tcx>(
         return;
     }
 
-    let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
+    let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
+        (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
+
+    if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
+        return;
+    }
 
     let mut app = Applicability::MachineApplicable;
     let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
@@ -787,8 +792,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
     }
 }
 
-// Peel raw casts if the remaining expression can be coerced to it
-fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
+// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
+// peeled or not.
+fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
     if !expr.span.from_expansion()
         && let ExprKind::Cast(inner, _) = expr.kind
         && let ty::RawPtr(target_ty, _) = expr_ty.kind()
@@ -796,8 +802,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty:
         && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
         && target_ty == inner_target_ty
     {
-        peel_raw_casts(cx, inner, inner_ty)
+        (peel_raw_casts(cx, inner, inner_ty).0, true)
     } else {
-        expr
+        (expr, false)
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 7f74a2fff9f..d8d813f9846 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::fmt;
 
 declare_clippy_lint! {
@@ -97,7 +97,7 @@ fn expr_as_ptr_offset_call<'tcx>(
         if path_segment.ident.name == sym::offset {
             return Some((arg_0, arg_1, Method::Offset));
         }
-        if path_segment.ident.name.as_str() == "wrapping_offset" {
+        if path_segment.ident.name == sym::wrapping_offset {
             return Some((arg_0, arg_1, Method::WrappingOffset));
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index d318897443d..c02e5e0621c 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
     eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
     pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
-    span_contains_cfg, span_contains_comment,
+    span_contains_cfg, span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -22,15 +22,14 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for expressions that could be replaced by the question mark operator.
+    /// Checks for expressions that could be replaced by the `?` operator.
     ///
     /// ### Why is this bad?
-    /// Question mark usage is more idiomatic.
+    /// Using the `?` operator is shorter and more idiomatic.
     ///
     /// ### Example
     /// ```ignore
@@ -47,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub QUESTION_MARK,
     style,
-    "checks for expressions that could be replaced by the question mark operator"
+    "checks for expressions that could be replaced by the `?` operator"
 }
 
 pub struct QuestionMark {
@@ -207,8 +206,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
             is_type_diagnostic_item(cx, caller_ty, smbl)
                 && expr_return_none_or_err(smbl, cx, if_then, caller, None)
                 && match smbl {
-                    sym::Option => call_sym.as_str() == "is_none",
-                    sym::Result => call_sym.as_str() == "is_err",
+                    sym::Option => call_sym == sym::is_none,
+                    sym::Result => call_sym == sym::is_err,
                     _ => false,
                 }
         },
@@ -280,7 +279,7 @@ fn expr_return_none_or_err(
 /// }
 /// ```
 ///
-/// If it matches, it will suggest to use the question mark operator instead
+/// If it matches, it will suggest to use the `?` operator instead
 fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr)
         && !is_else_clause(cx.tcx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index 0a974bf9d2f..96ea485d769 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for expressions that use the question mark operator and rejects them.
+    /// Checks for expressions that use the `?` operator and rejects them.
     ///
     /// ### Why restrict this?
-    /// Sometimes code wants to avoid the question mark operator because for instance a local
+    /// Sometimes code wants to avoid the `?` operator because for instance a local
     /// block requires a macro to re-throw errors to attach additional information to the
     /// error.
     ///
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.69.0"]
     pub QUESTION_MARK_USED,
     restriction,
-    "complains if the question mark operator is used"
+    "checks if the `?` operator is used"
 }
 
 declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
@@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
             }
 
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-            span_lint_and_then(
-                cx,
-                QUESTION_MARK_USED,
-                expr.span,
-                "question mark operator was used",
-                |diag| {
-                    diag.help("consider using a custom macro or match expression");
-                },
-            );
+            span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| {
+                diag.help("consider using a custom macro or match expression");
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 834ff2af0e8..89d945161f6 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -2,8 +2,9 @@ use std::fmt::Display;
 
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::paths::PathLookup;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths, sym};
+use clippy_utils::{path_def_id, paths};
 use rustc_ast::ast::{LitKind, StrStyle};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId};
@@ -121,17 +122,9 @@ impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX, REGEX_CREATION_IN_LOOPS]
 
 impl<'tcx> LateLintPass<'tcx> for Regex {
     fn check_crate(&mut self, cx: &LateContext<'tcx>) {
-        // We don't use `match_def_path` here because that relies on matching the exact path, which changed
-        // between regex 1.8 and 1.9
-        //
-        // `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only
-        // perform the operation once and store the results
-        let regex_crates = find_crates(cx.tcx, sym::regex);
-        let mut resolve = |path: &[&str], kind: RegexKind| {
-            for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) {
-                if let Some(id) = res.opt_def_id() {
-                    self.definitions.insert(id, kind);
-                }
+        let mut resolve = |path: &PathLookup, kind: RegexKind| {
+            for &id in path.get(cx) {
+                self.definitions.insert(id, kind);
             }
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index d8e8ead2912..122d97fdf81 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -5,7 +5,7 @@ use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
     binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor,
     leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg,
-    span_find_starting_semi,
+    span_find_starting_semi, sym,
 };
 use core::ops::ControlFlow;
 use rustc_ast::MetaItemInner;
@@ -22,7 +22,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
-use rustc_span::{BytePos, Pos, Span, sym};
+use rustc_span::{BytePos, Pos, Span};
 use std::borrow::Cow;
 use std::fmt::Display;
 
@@ -411,8 +411,8 @@ fn check_final_expr<'tcx>(
                         && let [tool, lint_name] = meta_item.path.segments.as_slice()
                         && tool.ident.name == sym::clippy
                         && matches!(
-                            lint_name.ident.name.as_str(),
-                            "needless_return" | "style" | "all" | "warnings"
+                            lint_name.ident.name,
+                            sym::needless_return | sym::style | sym::all | sym::warnings
                         )
                     {
                         // This is an expectation of the `needless_return` lint
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index a8c6518b592..a64b9b22378 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{get_trait_def_id, paths};
+use clippy_utils::paths;
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -32,9 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi {
         }) = item.kind
         {
             let did = trait_ref.path.res.def_id();
-            if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR)
-                && did == visit_did
-            {
+            if paths::SERDE_DE_VISITOR.matches(cx, did) {
                 let mut seen_str = None;
                 let mut seen_string = None;
                 for item in *items {
diff --git a/src/tools/clippy/clippy_lints/src/single_option_map.rs b/src/tools/clippy/clippy_lints/src/single_option_map.rs
index 1fb54950612..cc497c97a47 100644
--- a/src/tools/clippy/clippy_lints/src/single_option_map.rs
+++ b/src/tools/clippy/clippy_lints/src/single_option_map.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     ///     param * 2
     /// }
     /// ```
-    #[clippy::version = "1.86.0"]
+    #[clippy::version = "1.87.0"]
     pub SINGLE_OPTION_MAP,
     nursery,
     "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression."
diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
index 2d989b1cf0b..54d09ff9ee4 100644
--- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
@@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, is_no_std_crate};
+use clippy_utils::{is_no_std_crate, paths};
 use rustc_ast::{LitIntType, LitKind, UintTy};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr};
@@ -100,7 +100,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
             && let Some(start_snippet) = start.span.get_source_text(cx)
             && let Some(end_snippet) = end.span.get_source_text(cx)
         {
-            let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx.tcx, &["core", "iter", "Step"])
+            let should_emit_every_value = if let Some(step_def_id) = paths::ITER_STEP.only(cx)
                 && implements_trait(cx, ty, step_def_id, &[])
             {
                 true
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 d26288adb39..30a5fe4db27 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id,
-    span_contains_comment,
+    span_contains_comment, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -248,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
-            && path.ident.name.as_str() == "extend"
+            && path.ident.name == sym::extend
             && self.is_repeat_take(extend_arg)
         {
             self.slow_expression = Some(InitializationType::Extend(expr));
@@ -260,7 +259,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
-            && path.ident.name.as_str() == "resize"
+            && path.ident.name == sym::resize
             // Check that is filled with 0
             && is_integer_literal(fill_arg, 0)
         {
@@ -282,7 +281,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
         if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind
-            && take_path.ident.name.as_str() == "take"
+            && take_path.ident.name == sym::take
             // Check that take is applied to `repeat(0)`
             && self.is_repeat_zero(recv)
         {
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/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 43a3e696105..73a9fe71e00 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
         if !e.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
-            && path.ident.name.as_str() == "as_bytes"
+            && path.ident.name == sym::as_bytes
             && let ExprKind::Lit(lit) = &receiver.kind
             && let LitKind::Str(lit_content, _) = &lit.node
         {
@@ -332,9 +332,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if let ExprKind::MethodCall(path, recv, [], _) = &e.kind
-            && path.ident.name.as_str() == "into_bytes"
+            && path.ident.name == sym::into_bytes
             && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind
-            && matches!(path.ident.name.as_str(), "to_owned" | "to_string")
+            && matches!(path.ident.name, sym::to_owned | sym::to_string)
             && let ExprKind::Lit(lit) = &recv.kind
             && let LitKind::Str(lit_content, _) = &lit.node
             && lit_content.as_str().is_ascii()
@@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         let tyckres = cx.typeck_results();
         if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind
-            && path.ident.name.as_str() == "split_whitespace"
+            && path.ident.name == sym::split_whitespace
             && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id)
             && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 9993e6ae18b..7d7d74f27b3 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -1,11 +1,12 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::match_def_path;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_in_const_context, paths, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -33,34 +34,35 @@ declare_clippy_lint! {
     "`char.is_digit()` is clearer"
 }
 
-declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
+impl_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
+
+pub(crate) struct ToDigitIsSome {
+    msrv: Msrv,
+}
+
+impl ToDigitIsSome {
+    pub(crate) fn new(conf: &'static Conf) -> Self {
+        Self { msrv: conf.msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind
-            && is_some_path.ident.name.as_str() == "is_some"
+            && is_some_path.ident.name == sym::is_some
         {
-            let match_result = match &to_digit_expr.kind {
+            let match_result = match to_digit_expr.kind {
                 hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
-                    if to_digits_path.ident.name.as_str() == "to_digit"
-                        && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg)
-                        && *char_arg_ty.kind() == ty::Char
+                    if to_digits_path.ident.name == sym::to_digit
+                        && cx.typeck_results().expr_ty_adjusted(char_arg).is_char()
                     {
-                        Some((true, *char_arg, radix_arg))
+                        Some((true, char_arg, radix_arg))
                     } else {
                         None
                     }
                 },
                 hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => {
-                    if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
-                        && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
-                        && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
-                        && match_def_path(
-                            cx,
-                            to_digits_def_id,
-                            &["core", "char", "methods", "<impl char>", "to_digit"],
-                        )
-                    {
+                    if paths::CHAR_TO_DIGIT.matches_path(cx, to_digits_call) {
                         Some((false, char_arg, radix_arg))
                     } else {
                         None
@@ -69,7 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                 _ => None,
             };
 
-            if let Some((is_method_call, char_arg, radix_arg)) = match_result {
+            if let Some((is_method_call, char_arg, radix_arg)) = match_result
+                && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_CHAR_IS_DIGIT))
+            {
                 let mut applicability = Applicability::MachineApplicable;
                 let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability);
                 let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 8aac3a59102..45e54302e32 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -15,7 +15,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::{BytePos, Span};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -282,18 +282,18 @@ impl TraitBounds {
                     .iter()
                     .copied()
                     .chain(p.bounds.iter())
-                    .filter_map(get_trait_info_from_bound)
-                    .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability))
+                    .map(|bound| snippet_with_applicability(cx, bound.span(), "_", &mut applicability))
                     .join(" + ");
                 let hint_string = format!(
                     "consider combining the bounds: `{}: {trait_bounds}`",
                     snippet(cx, p.bounded_ty.span, "_"),
                 );
+                let ty_name = snippet(cx, p.bounded_ty.span, "_");
                 span_lint_and_help(
                     cx,
                     TYPE_REPETITION_IN_BOUNDS,
                     bound.span,
-                    "this type has already been used as a bound predicate",
+                    format!("type `{ty_name}` has already been used as a bound predicate"),
                     None,
                     hint_string,
                 );
@@ -395,15 +395,7 @@ impl Hash for ComparableTraitRef<'_, '_> {
 fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
     if let GenericBound::Trait(t) = bound {
         let trait_path = t.trait_ref.path;
-        let trait_span = {
-            let path_span = trait_path.span;
-            if let BoundPolarity::Maybe(_) = t.modifiers.polarity {
-                path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?`
-            } else {
-                path_span
-            }
-        };
-        Some((trait_path.res, trait_path.segments, trait_span))
+        Some((trait_path.res, trait_path.segments, t.span))
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index 81c0a57083e..535c044f49e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_normalizable;
-use clippy_utils::{eq_expr_value, path_to_local};
+use clippy_utils::{eq_expr_value, path_to_local, sym};
 use rustc_abi::WrappingRange;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -43,7 +42,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_
             binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs)
         },
         ExprKind::MethodCall(path, receiver, [arg], _)
-            if path.ident.name.as_str() == "contains"
+            if path.ident.name == sym::contains
                 // ... `contains` called on some kind of range
                 && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
                 && let lang_items = cx.tcx.lang_items()
@@ -81,11 +80,9 @@ pub(super) fn check<'tcx>(
     if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr)
         && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
         && cx.typeck_results().expr_ty(receiver).is_bool()
-        && path.ident.name.as_str() == "then_some"
+        && path.ident.name == sym::then_some
         && is_local_with_projections(transmutable)
         && binops_with_local(cx, transmutable, receiver)
-        && is_normalizable(cx, cx.param_env, from_ty)
-        && is_normalizable(cx, cx.param_env, to_ty)
         // we only want to lint if the target type has a niche that is larger than the one of the source type
         // e.g. `u8` to `NonZero<u8>` should lint, but `NonZero<u8>` to `u8` should not
         && let Ok(from_layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(from_ty))
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index f2da8d35cb4..d5112e2c3f9 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -1,13 +1,9 @@
 mod crosspointer_transmute;
 mod eager_transmute;
 mod missing_transmute_annotations;
-mod transmute_float_to_int;
 mod transmute_int_to_bool;
-mod transmute_int_to_char;
-mod transmute_int_to_float;
 mod transmute_int_to_non_zero;
 mod transmute_null_to_fn;
-mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
@@ -143,40 +139,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for transmutes from an integer to a `char`.
-    ///
-    /// ### Why is this bad?
-    /// Not every integer is a Unicode scalar value.
-    ///
-    /// ### Known problems
-    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
-    /// as it needs to validate the input.
-    /// If you are certain that the input is always a valid Unicode scalar value,
-    /// use [`from_u32_unchecked`] which is as fast as `transmute`
-    /// but has a semantically meaningful name.
-    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
-    ///
-    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
-    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
-    ///
-    /// ### Example
-    /// ```no_run
-    /// let x = 1_u32;
-    /// unsafe {
-    ///     let _: char = std::mem::transmute(x); // where x: u32
-    /// }
-    ///
-    /// // should be:
-    /// let _ = std::char::from_u32(x).unwrap();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TRANSMUTE_INT_TO_CHAR,
-    complexity,
-    "transmutes from an integer to a `char`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks for transmutes from a `&[u8]` to a `&str`.
     ///
     /// ### Why is this bad?
@@ -234,29 +196,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for transmutes from an integer to a float.
-    ///
-    /// ### Why is this bad?
-    /// Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
-    /// and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let _: f32 = std::mem::transmute(1_u32); // where x: u32
-    /// }
-    ///
-    /// // should be:
-    /// let _: f32 = f32::from_bits(1_u32);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub TRANSMUTE_INT_TO_FLOAT,
-    complexity,
-    "transmutes from an integer to a float"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks for transmutes from `T` to `NonZero<T>`, and suggests the `new_unchecked`
     /// method instead.
     ///
@@ -282,52 +221,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for transmutes from a float to an integer.
-    ///
-    /// ### Why is this bad?
-    /// Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
-    /// and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let _: u32 = std::mem::transmute(1f32);
-    /// }
-    ///
-    /// // should be:
-    /// let _: u32 = 1f32.to_bits();
-    /// ```
-    #[clippy::version = "1.41.0"]
-    pub TRANSMUTE_FLOAT_TO_INT,
-    complexity,
-    "transmutes from a float to an integer"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmutes from a number to an array of `u8`
-    ///
-    /// ### Why this is bad?
-    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
-    /// is intuitive and safe.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// unsafe {
-    ///     let x: [u8; 8] = std::mem::transmute(1i64);
-    /// }
-    ///
-    /// // should be
-    /// let x: [u8; 8] = 0i64.to_ne_bytes();
-    /// ```
-    #[clippy::version = "1.58.0"]
-    pub TRANSMUTE_NUM_TO_BYTES,
-    complexity,
-    "transmutes from a number to an array of `u8`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks for transmutes from a pointer to a pointer, or
     /// from a reference to a reference.
     ///
@@ -581,13 +474,9 @@ impl_lint_pass!(Transmute => [
     TRANSMUTE_PTR_TO_PTR,
     USELESS_TRANSMUTE,
     WRONG_TRANSMUTE,
-    TRANSMUTE_INT_TO_CHAR,
     TRANSMUTE_BYTES_TO_STR,
     TRANSMUTE_INT_TO_BOOL,
-    TRANSMUTE_INT_TO_FLOAT,
     TRANSMUTE_INT_TO_NON_ZERO,
-    TRANSMUTE_FLOAT_TO_INT,
-    TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
@@ -632,14 +521,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 | transmute_null_to_fn::check(cx, e, arg, to_ty)
                 | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
                 | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
-                | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv)
                 | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
-                | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
                 | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
-                | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
-                | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv)
                 | (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
                     || transmute_undefined_repr::check(cx, e, from_ty, to_ty))
                 | (eager_transmute::check(cx, e, arg, from_ty, to_ty));
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
deleted file mode 100644
index df2f681a162..00000000000
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use super::TRANSMUTE_FLOAT_TO_INT;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_ast as ast;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, UnOp};
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_float_to_int` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    mut arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Float(float_ty), ty::Int(_) | ty::Uint(_))
-            if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) =>
-        {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_FLOAT_TO_INT,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let mut sugg = sugg::Sugg::hir(cx, arg, "..");
-
-                    if let ExprKind::Unary(UnOp::Neg, inner_expr) = &arg.kind {
-                        arg = inner_expr;
-                    }
-
-                    if let ExprKind::Lit(lit) = &arg.kind
-                        // if the expression is a float literal and it is unsuffixed then
-                        // add a suffix so the suggestion is valid and unambiguous
-                        && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node
-                    {
-                        let op = format!("{sugg}{}", float_ty.name_str()).into();
-                        match sugg {
-                            sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
-                            _ => sugg = sugg::Sugg::NonParen(op),
-                        }
-                    }
-
-                    sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_paren()).into());
-
-                    // cast the result of `to_bits` if `to_ty` is signed
-                    sugg = if let ty::Int(int_ty) = to_ty.kind() {
-                        sugg.as_ty(int_ty.name_str().to_string())
-                    } else {
-                        sugg
-                    };
-
-                    diag.span_suggestion(e.span, "consider using", sugg, Applicability::Unspecified);
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
deleted file mode 100644
index 81d10a7d5bd..00000000000
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use super::TRANSMUTE_INT_TO_CHAR;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{std_or_core, sugg};
-use rustc_ast as ast;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_int_to_char` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) if !const_context => {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_INT_TO_CHAR,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `char`"),
-                |diag| {
-                    let Some(top_crate) = std_or_core(cx) else { return };
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let arg = if let ty::Int(_) = from_ty.kind() {
-                        arg.as_ty(ast::UintTy::U32.name_str())
-                    } else {
-                        arg
-                    };
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using",
-                        format!("{top_crate}::char::from_u32({arg}).unwrap()"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
deleted file mode 100644
index aaa95396b4b..00000000000
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use super::TRANSMUTE_INT_TO_FLOAT;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
-
-/// Checks for `transmute_int_to_float` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => {
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_INT_TO_FLOAT,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    let arg = if let ty::Int(int_ty) = from_ty.kind() {
-                        arg.as_ty(format!(
-                            "u{}",
-                            int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())
-                        ))
-                    } else {
-                        arg
-                    };
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using",
-                        format!("{to_ty}::from_bits({arg})"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
deleted file mode 100644
index d72be270b73..00000000000
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use super::TRANSMUTE_NUM_TO_BYTES;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::sugg;
-use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, UintTy};
-
-/// Checks for `transmute_int_to_float` lint.
-/// Returns `true` if it's triggered, otherwise returns `false`.
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-    arg: &'tcx Expr<'_>,
-    const_context: bool,
-    msrv: Msrv,
-) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
-            if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
-                return false;
-            }
-            if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV)
-            {
-                return false;
-            }
-
-            span_lint_and_then(
-                cx,
-                TRANSMUTE_NUM_TO_BYTES,
-                e.span,
-                format!("transmute from a `{from_ty}` to a `{to_ty}`"),
-                |diag| {
-                    let arg = sugg::Sugg::hir(cx, arg, "..");
-                    diag.span_suggestion(
-                        e.span,
-                        "consider using `to_ne_bytes()`",
-                        format!("{arg}.to_ne_bytes()"),
-                        Applicability::Unspecified,
-                    );
-                },
-            );
-            true
-        },
-        _ => false,
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 3147058b4cd..c1c7cc51656 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -385,7 +385,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let right: std::borrow::Cow<'_, [u8]>;
     /// ```
-    #[clippy::version = "1.85.0"]
+    #[clippy::version = "1.87.0"]
     pub OWNED_COW,
     style,
     "needlessly owned Cow type"
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 769244c675e..f13042a6fa6 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -19,61 +19,58 @@ pub(super) fn check<'tcx>(
     def_id: DefId,
     box_size_threshold: u64,
 ) -> bool {
-    if cx.tcx.is_diagnostic_item(sym::Vec, def_id) {
-        if let Some(last) = last_path_segment(qpath).args
-            // Get the _ part of Vec<_>
-            && let Some(GenericArg::Type(ty)) = last.args.first()
-            // extract allocator from the Vec for later
-            && let vec_alloc_ty = last.args.get(1)
-            // ty is now _ at this point
-            && let TyKind::Path(ref ty_qpath) = ty.kind
-            && let res = cx.qpath_res(ty_qpath, ty.hir_id)
-            && let Some(def_id) = res.opt_def_id()
-            && Some(def_id) == cx.tcx.lang_items().owned_box()
-            // At this point, we know ty is Box<T>, now get T
-            && let Some(last) = last_path_segment(ty_qpath).args
-            && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
-            // extract allocator from the Box for later
-            && let boxed_alloc_ty = last.args.get(1)
-            // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
-            && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
-            && !ty_ty.has_escaping_bound_vars()
-            && ty_ty.is_sized(cx.tcx, cx.typing_env())
-            && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
-            && ty_ty_size < box_size_threshold
-            // https://github.com/rust-lang/rust-clippy/issues/7114
-            && match (vec_alloc_ty, boxed_alloc_ty) {
-                (None, None) => true,
-                // this is in the event that we have something like
-                // Vec<_, Global>, in which case is equivalent to
-                // Vec<_>
-                (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
-                    if let TyKind::Path(path) = inner.kind
-                        && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
-                        cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
-                    } else {
-                        false
-                    }
-                },
-                (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
-                    // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
-                    lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
-                _ => false
-            }
-        {
-            span_lint_and_sugg(
-                cx,
-                VEC_BOX,
-                hir_ty.span,
-                "`Vec<T>` is already on the heap, the boxing is unnecessary",
-                "try",
-                format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
-                Applicability::Unspecified,
-            );
-            true
-        } else {
-            false
+    if cx.tcx.is_diagnostic_item(sym::Vec, def_id)
+        && let Some(last) = last_path_segment(qpath).args
+        // Get the _ part of Vec<_>
+        && let Some(GenericArg::Type(ty)) = last.args.first()
+        // extract allocator from the Vec for later
+        && let vec_alloc_ty = last.args.get(1)
+        // ty is now _ at this point
+        && let TyKind::Path(ref ty_qpath) = ty.kind
+        && let res = cx.qpath_res(ty_qpath, ty.hir_id)
+        && let Some(def_id) = res.opt_def_id()
+        && Some(def_id) == cx.tcx.lang_items().owned_box()
+        // At this point, we know ty is Box<T>, now get T
+        && let Some(last) = last_path_segment(ty_qpath).args
+        && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
+        // extract allocator from the Box for later
+        && let boxed_alloc_ty = last.args.get(1)
+        // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+        && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty())
+        && !ty_ty.has_escaping_bound_vars()
+        && ty_ty.is_sized(cx.tcx, cx.typing_env())
+        && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
+        && ty_ty_size < box_size_threshold
+        // https://github.com/rust-lang/rust-clippy/issues/7114
+        && match (vec_alloc_ty, boxed_alloc_ty) {
+            (None, None) => true,
+            // this is in the event that we have something like
+            // Vec<_, Global>, in which case is equivalent to
+            // Vec<_>
+            (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
+                if let TyKind::Path(path) = inner.kind
+                    && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
+                    cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did)
+                } else {
+                    false
+                }
+            },
+            (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
+                // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay
+                lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()),
+            _ => false
         }
+    {
+        span_lint_and_sugg(
+            cx,
+            VEC_BOX,
+            hir_ty.span,
+            "`Vec<T>` is already on the heap, the boxing is unnecessary",
+            "try",
+            format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
+            Applicability::Unspecified,
+        );
+        true
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 7803d5115c9..cee4a53f03c 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
-use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while};
+use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
 use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
 declare_clippy_lint! {
@@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
 
 fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
     is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
-        && path.ident.name.as_str() == "reserve"
+        && path.ident.name == sym::reserve
 }
 
 /// Returns self if the expression is `Vec::set_len()`
@@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
         ExprKind::MethodCall(path, self_expr, [arg], _) => {
             let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
             if is_type_diagnostic_item(cx, self_type, sym::Vec)
-                && path.ident.name.as_str() == "set_len"
+                && path.ident.name == sym::set_len
                 && !is_integer_literal(arg, 0)
             {
                 Some((self_expr, expr.span))
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index 6dcc1195a70..48b532968cb 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::sym;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 
@@ -7,11 +8,12 @@ use super::UNIT_CMP;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
-        if let Some(macro_call) = root_macro_call_first_node(cx, expr) {
-            let macro_name = cx.tcx.item_name(macro_call.def_id);
-            let result = match macro_name.as_str() {
-                "assert_eq" | "debug_assert_eq" => "succeed",
-                "assert_ne" | "debug_assert_ne" => "fail",
+        if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+        {
+            let result = match diag_name {
+                sym::assert_eq_macro | sym::debug_assert_eq_macro => "succeed",
+                sym::assert_ne_macro | sym::debug_assert_ne_macro => "fail",
                 _ => return,
             };
             let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
@@ -24,7 +26,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 cx,
                 UNIT_CMP,
                 macro_call.span,
-                format!("`{macro_name}` of unit values detected. This will always {result}"),
+                format!(
+                    "`{}` of unit values detected. This will always {result}",
+                    cx.tcx.item_name(macro_call.def_id)
+                ),
             );
         }
         return;
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 1c1c841e964..8ceaa3dc58e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_def_id_trait_method;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Node, YieldSource};
+use rustc_hir::{Body, Defaultness, Expr, ExprKind, FnDecl, HirId, Node, TraitItem, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_session::impl_lint_pass;
@@ -116,7 +116,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
         span: Span,
         def_id: LocalDefId,
     ) {
-        if !span.from_expansion() && fn_kind.asyncness().is_async() && !is_def_id_trait_method(cx, def_id) {
+        if !span.from_expansion()
+            && fn_kind.asyncness().is_async()
+            && !is_def_id_trait_method(cx, def_id)
+            && !is_default_trait_impl(cx, def_id)
+        {
             let mut visitor = AsyncFnVisitor {
                 cx,
                 found_await: false,
@@ -189,3 +193,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
         }
     }
 }
+
+fn is_default_trait_impl(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    matches!(
+        cx.tcx.hir_node_by_def_id(def_id),
+        Node::TraitItem(TraitItem {
+            defaultness: Defaultness::Default { .. },
+            ..
+        })
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 2d88c490b1a..5e1cb9e54f5 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::{is_res_lang_ctor, is_trait_method, match_def_path, match_trait_method, paths, peel_blocks};
+use clippy_utils::{is_res_lang_ctor, paths, peel_blocks};
 use hir::{ExprKind, HirId, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -93,14 +93,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                 return;
             }
 
-            let async_paths: [&[&str]; 4] = [
+            let async_paths = [
                 &paths::TOKIO_IO_ASYNCREADEXT,
                 &paths::TOKIO_IO_ASYNCWRITEEXT,
                 &paths::FUTURES_IO_ASYNCREADEXT,
                 &paths::FUTURES_IO_ASYNCWRITEEXT,
             ];
 
-            if async_paths.into_iter().any(|path| match_def_path(cx, trait_id, path)) {
+            if async_paths.into_iter().any(|path| path.matches(cx, trait_id)) {
                 return;
             }
         }
@@ -226,7 +226,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     if is_panic(cx, macro_call.def_id) {
         return !cx.tcx.hir_is_inside_const_context(expr.hir_id);
     }
-    matches!(cx.tcx.item_name(macro_call.def_id).as_str(), "unreachable")
+    cx.tcx.is_diagnostic_item(sym::unreachable_macro, macro_call.def_id)
 }
 
 fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
@@ -291,19 +291,28 @@ fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> {
         },
     };
 
-    match (
-        is_trait_method(cx, call, sym::IoRead),
-        is_trait_method(cx, call, sym::IoWrite),
-        match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
-            || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT),
-        match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT)
-            || match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT),
-    ) {
-        (true, _, _, _) => Some(IoOp::SyncRead(vectorized)),
-        (_, true, _, _) => Some(IoOp::SyncWrite(vectorized)),
-        (_, _, true, _) => Some(IoOp::AsyncRead(vectorized)),
-        (_, _, _, true) => Some(IoOp::AsyncWrite(vectorized)),
-        _ => None,
+    if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(call.hir_id)
+        && let Some(trait_def_id) = cx.tcx.trait_of_item(method_def_id)
+    {
+        if let Some(diag_name) = cx.tcx.get_diagnostic_name(trait_def_id) {
+            match diag_name {
+                sym::IoRead => Some(IoOp::SyncRead(vectorized)),
+                sym::IoWrite => Some(IoOp::SyncWrite(vectorized)),
+                _ => None,
+            }
+        } else if paths::FUTURES_IO_ASYNCREADEXT.matches(cx, trait_def_id)
+            || paths::TOKIO_IO_ASYNCREADEXT.matches(cx, trait_def_id)
+        {
+            Some(IoOp::AsyncRead(vectorized))
+        } else if paths::TOKIO_IO_ASYNCWRITEEXT.matches(cx, trait_def_id)
+            || paths::FUTURES_IO_ASYNCWRITEEXT.matches(cx, trait_def_id)
+        {
+            Some(IoOp::AsyncWrite(vectorized))
+        } else {
+            None
+        }
+    } else {
+        None
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index d0067b1a65e..12da891a71b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,6 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::sym;
 use clippy_utils::visitors::is_local_used;
 use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
         let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
         let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
             clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| {
-                if let Some(macro_call) = root_macro_call_first_node(cx, e) {
-                    if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
-                        ControlFlow::Break(())
-                    } else {
-                        ControlFlow::Continue(())
-                    }
+                if let Some(macro_call) = root_macro_call_first_node(cx, e)
+                    && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id)
+                {
+                    ControlFlow::Break(())
                 } else {
                     ControlFlow::Continue(())
                 }
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index d5309aade7a..9859ddfdf7b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -1,11 +1,18 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{SpanRangeExt, position_before_rarrow};
-use rustc_ast::visit::FnKind;
-use rustc_ast::{ClosureBinder, ast};
+use clippy_utils::{is_never_expr, is_unit_expr};
+use rustc_ast::{Block, StmtKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{
+    AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term,
+    Ty, TyKind,
+};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span};
+use rustc_span::edition::Edition;
+use rustc_span::{BytePos, Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,27 +41,89 @@ declare_clippy_lint! {
 
 declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
 
-impl EarlyLintPass for UnusedUnit {
-    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
-        if let ast::FnRetTy::Ty(ref ty) = kind.decl().output
-            && let ast::TyKind::Tup(ref vals) = ty.kind
-            && vals.is_empty()
-            && !ty.span.from_expansion()
-            && get_def(span) == get_def(ty.span)
+impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        span: Span,
+        def_id: LocalDefId,
+    ) {
+        if let FnRetTy::Return(hir_ty) = decl.output
+            && is_unit_ty(hir_ty)
+            && !hir_ty.span.from_expansion()
+            && get_def(span) == get_def(hir_ty.span)
         {
             // implicit types in closure signatures are forbidden when `for<...>` is present
-            if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
+            if let FnKind::Closure = kind
+                && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id)
+                && let ExprKind::Closure(closure) = expr.kind
+                && !closure.bound_generic_params.is_empty()
+            {
+                return;
+            }
+
+            // unit never type fallback is no longer supported since Rust 2024. For more information,
+            // see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>
+            if cx.tcx.sess.edition() >= Edition::Edition2024
+                && let ExprKind::Block(block, _) = body.value.kind
+                && let Some(expr) = block.expr
+                && is_never_expr(cx, expr).is_some()
+            {
                 return;
             }
 
-            lint_unneeded_unit_return(cx, ty, span);
+            lint_unneeded_unit_return(cx, hir_ty.span, span);
         }
     }
 
-    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        if let Some(stmt) = block.stmts.last()
-            && let ast::StmtKind::Expr(ref expr) = stmt.kind
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind
             && is_unit_expr(expr)
+            && !expr.span.from_expansion()
+        {
+            span_lint_and_sugg(
+                cx,
+                UNUSED_UNIT,
+                expr.span,
+                "unneeded `()`",
+                "remove the `()`",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
+        let segments = &poly.trait_ref.path.segments;
+
+        if segments.len() == 1
+            && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
+            && let Some(args) = segments[0].args
+            && args.parenthesized == GenericArgsParentheses::ParenSugar
+            && let constraints = &args.constraints
+            && constraints.len() == 1
+            && constraints[0].ident.name == sym::Output
+            && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind
+            && args.span_ext.hi() != poly.span.hi()
+            && !hir_ty.span.from_expansion()
+            && is_unit_ty(hir_ty)
+        {
+            lint_unneeded_unit_return(cx, hir_ty.span, poly.span);
+        }
+    }
+}
+
+impl EarlyLintPass for UnusedUnit {
+    /// Check for unit expressions in blocks. This is left in the early pass because some macros
+    /// expand its inputs as-is, making it invisible to the late pass. See #4076.
+    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
+        if let Some(stmt) = block.stmts.last()
+            && let StmtKind::Expr(expr) = &stmt.kind
+            && let rustc_ast::ExprKind::Tup(inner) = &expr.kind
+            && inner.is_empty()
             && let ctxt = block.span.ctxt()
             && stmt.span.ctxt() == ctxt
             && expr.span.ctxt() == ctxt
@@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit {
             );
         }
     }
+}
 
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        match e.kind {
-            ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => {
-                if is_unit_expr(expr) && !expr.span.from_expansion() {
-                    span_lint_and_sugg(
-                        cx,
-                        UNUSED_UNIT,
-                        expr.span,
-                        "unneeded `()`",
-                        "remove the `()`",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            },
-            _ => (),
-        }
-    }
-
-    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
-        let segments = &poly.trait_ref.path.segments;
-
-        if segments.len() == 1
-            && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
-            && let Some(args) = &segments[0].args
-            && let ast::GenericArgs::Parenthesized(generic_args) = &**args
-            && let ast::FnRetTy::Ty(ty) = &generic_args.output
-            && ty.kind.is_unit()
-        {
-            lint_unneeded_unit_return(cx, ty, generic_args.span);
-        }
-    }
+fn is_unit_ty(ty: &Ty<'_>) -> bool {
+    matches!(ty.kind, TyKind::Tup([]))
 }
 
 // get the def site
@@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option<Span> {
     }
 }
 
-// is this expr a `()` unit?
-fn is_unit_expr(expr: &ast::Expr) -> bool {
-    if let ast::ExprKind::Tup(ref vals) = expr.kind {
-        vals.is_empty()
-    } else {
-        false
-    }
-}
-
-fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
+fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) {
     let (ret_span, appl) =
-        span.with_hi(ty.span.hi())
+        span.with_hi(ty_span.hi())
             .get_source_text(cx)
-            .map_or((ty.span, Applicability::MaybeIncorrect), |src| {
-                position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+            .map_or((ty_span, Applicability::MaybeIncorrect), |src| {
+                position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| {
                     (
                         #[expect(clippy::cast_possible_truncation)]
-                        ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+                        ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)),
                         Applicability::MachineApplicable,
                     )
                 })
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ce82b56eb94..c641d4e55b9 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -4,15 +4,15 @@ use clippy_utils::usage::is_potentially_local_place;
 use clippy_utils::{higher, path_to_local, sym};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
-use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -111,7 +111,7 @@ struct UnwrapInfo<'tcx> {
     /// The check, like `x.is_ok()`
     check: &'tcx Expr<'tcx>,
     /// The check's name, like `is_ok`
-    check_name: &'tcx PathSegment<'tcx>,
+    check_name: Symbol,
     /// The branch where the check takes place, like `if x.is_ok() { .. }`
     branch: &'tcx Expr<'tcx>,
     /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
@@ -133,12 +133,12 @@ fn collect_unwrap_info<'tcx>(
     invert: bool,
     is_entire_condition: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
-    fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym::Option) && ["is_some", "is_none"].contains(&method_name)
+    fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+        is_type_diagnostic_item(cx, ty, sym::Option) && matches!(method_name, sym::is_none | sym::is_some)
     }
 
-    fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym::Result) && ["is_ok", "is_err"].contains(&method_name)
+    fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+        is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok)
     }
 
     if let ExprKind::Binary(op, left, right) = &expr.kind {
@@ -155,14 +155,10 @@ fn collect_unwrap_info<'tcx>(
     } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind
         && let Some(local_id) = path_to_local(receiver)
         && let ty = cx.typeck_results().expr_ty(receiver)
-        && let name = method_name.ident.as_str()
+        && let name = method_name.ident.name
         && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name))
     {
-        let unwrappable = match name {
-            "is_some" | "is_ok" => true,
-            "is_err" | "is_none" => false,
-            _ => unreachable!(),
-        };
+        let unwrappable = matches!(name, sym::is_some | sym::is_ok);
         let safe_to_unwrap = unwrappable != invert;
         let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
             UnwrappableKind::Option
@@ -174,7 +170,7 @@ fn collect_unwrap_info<'tcx>(
             local_id,
             if_expr,
             check: expr,
-            check_name: method_name,
+            check_name: name,
             branch,
             safe_to_unwrap,
             kind,
@@ -184,12 +180,12 @@ fn collect_unwrap_info<'tcx>(
     Vec::new()
 }
 
-/// A HIR visitor delegate that checks if a local variable of type `Option<_>` is mutated,
-/// *except* for if `Option::as_mut` is called.
+/// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated,
+/// *except* for if `.as_mut()` is called.
 /// The reason for why we allow that one specifically is that `.as_mut()` cannot change
-/// the option to `None`, and that is important because this lint relies on the fact that
+/// the variant, and that is important because this lint relies on the fact that
 /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if
-/// the option is changed to None between `is_some` and `unwrap`.
+/// the option is changed to None between `is_some` and `unwrap`, ditto for `Result`.
 /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.)
 struct MutationVisitor<'tcx> {
     is_mutated: bool,
@@ -198,17 +194,17 @@ struct MutationVisitor<'tcx> {
 }
 
 /// Checks if the parent of the expression pointed at by the given `HirId` is a call to
-/// `Option::as_mut`.
+/// `.as_mut()`.
 ///
 /// Used by the mutation visitor to specifically allow `.as_mut()` calls.
 /// In particular, the `HirId` that the visitor receives is the id of the local expression
 /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
 /// expression: that will be where the actual method call is.
-fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
+fn is_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
     if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
         && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind
     {
-        path.ident.name.as_str() == "as_mut"
+        path.ident.name == sym::as_mut
     } else {
         false
     }
@@ -218,14 +214,16 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
     fn borrow(&mut self, cat: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
         if let ty::BorrowKind::Mutable = bk
             && is_potentially_local_place(self.local_id, &cat.place)
-            && !is_option_as_mut_use(self.tcx, diag_expr_id)
+            && !is_as_mut_use(self.tcx, diag_expr_id)
         {
             self.is_mutated = true;
         }
     }
 
-    fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {
-        self.is_mutated = true;
+    fn mutate(&mut self, cat: &PlaceWithHirId<'tcx>, _: HirId) {
+        if is_potentially_local_place(self.local_id, &cat.place) {
+            self.is_mutated = true;
+        }
     }
 
     fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
@@ -276,12 +274,10 @@ enum AsRefKind {
 /// If it isn't, the expression itself is returned.
 fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Option<AsRefKind>) {
     if let ExprKind::MethodCall(path, recv, [], _) = expr.kind {
-        if path.ident.name == sym::as_ref {
-            (recv, Some(AsRefKind::AsRef))
-        } else if path.ident.name.as_str() == "as_mut" {
-            (recv, Some(AsRefKind::AsMut))
-        } else {
-            (expr, None)
+        match path.ident.name {
+            sym::as_ref => (recv, Some(AsRefKind::AsRef)),
+            sym::as_mut => (recv, Some(AsRefKind::AsMut)),
+            _ => (expr, None),
         }
     } else {
         (expr, None)
@@ -296,6 +292,10 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
         if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) {
             return;
         }
+        // Skip checking inside closures since they are visited through `Unwrap::check_fn()` already.
+        if matches!(expr.kind, ExprKind::Closure(_)) {
+            return;
+        }
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) {
             walk_expr(self, cond);
             self.visit_branch(expr, cond, then, false);
@@ -332,8 +332,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
                         expr.span,
                         format!(
                             "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
-                            method_name.ident.name,
-                            unwrappable.check_name.ident.as_str(),
+                            method_name.ident.name, unwrappable.check_name,
                         ),
                         |diag| {
                             if is_entire_condition {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index b7dcd2ffb0e..812c4df4ddd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -1,16 +1,18 @@
-use clippy_utils::{get_attr, higher};
+use clippy_utils::{MaybePath, get_attr, higher, path_def_id};
+use itertools::Itertools;
 use rustc_ast::LitIntType;
 use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
 use rustc_hir::{
     self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
-    FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
+    FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::{Ident, Symbol};
 use std::cell::Cell;
-use std::fmt::{Display, Formatter, Write as _};
+use std::fmt::{Display, Formatter};
 
 declare_lint_pass!(
     /// ### What it does
@@ -148,6 +150,15 @@ fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_,
     }
 }
 
+fn paths_static_name(cx: &LateContext<'_>, id: DefId) -> String {
+    cx.get_def_path(id)
+        .iter()
+        .map(Symbol::as_str)
+        .filter(|s| !s.starts_with('<'))
+        .join("_")
+        .to_uppercase()
+}
+
 struct Binding<T> {
     name: String,
     value: T,
@@ -257,11 +268,44 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         chain!(self, "{symbol}.as_str() == {:?}", symbol.value.as_str());
     }
 
-    fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
+    fn qpath<'p>(&self, qpath: &Binding<&QPath<'_>>, has_hir_id: &Binding<&impl MaybePath<'p>>) {
         if let QPath::LangItem(lang_item, ..) = *qpath.value {
             chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
-        } else if let Ok(path) = path_to_string(qpath.value) {
-            chain!(self, "match_qpath({qpath}, &[{}])", path);
+        } else if let Some(def_id) = self.cx.qpath_res(qpath.value, has_hir_id.value.hir_id()).opt_def_id()
+            && !def_id.is_local()
+        {
+            bind!(self, def_id);
+            chain!(
+                self,
+                "let Some({def_id}) = cx.qpath_res({qpath}, {has_hir_id}.hir_id).opt_def_id()"
+            );
+            if let Some(name) = self.cx.tcx.get_diagnostic_name(def_id.value) {
+                chain!(self, "cx.tcx.is_diagnostic_item(sym::{name}, {def_id})");
+            } else {
+                chain!(
+                    self,
+                    "paths::{}.matches(cx, {def_id}) // Add the path to `clippy_utils::paths` if needed",
+                    paths_static_name(self.cx, def_id.value)
+                );
+            }
+        }
+    }
+
+    fn maybe_path<'p>(&self, path: &Binding<&impl MaybePath<'p>>) {
+        if let Some(id) = path_def_id(self.cx, path.value)
+            && !id.is_local()
+        {
+            if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) {
+                chain!(self, "is_path_lang_item(cx, {path}, LangItem::{}", lang.name());
+            } else if let Some(name) = self.cx.tcx.get_diagnostic_name(id) {
+                chain!(self, "is_path_diagnostic_item(cx, {path}, sym::{name})");
+            } else {
+                chain!(
+                    self,
+                    "paths::{}.matches_path(cx, {path}) // Add the path to `clippy_utils::paths` if needed",
+                    paths_static_name(self.cx, id)
+                );
+            }
         }
     }
 
@@ -270,7 +314,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ConstArgKind::Path(ref qpath) => {
                 bind!(self, qpath);
                 chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind");
-                self.qpath(qpath);
             },
             ConstArgKind::Anon(anon_const) => {
                 bind!(self, anon_const);
@@ -394,12 +437,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 bind!(self, let_expr);
                 kind!("Let({let_expr})");
                 self.pat(field!(let_expr.pat));
-                // Does what ExprKind::Cast does, only adds a clause for the type
-                // if it's a path
-                if let Some(TyKind::Path(qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
-                    bind!(self, qpath);
-                    chain!(self, "let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind");
-                    self.qpath(qpath);
+                if let Some(ty) = let_expr.value.ty {
+                    bind!(self, ty);
+                    chain!(self, "let Some({ty}) = {let_expr}.ty");
+                    self.maybe_path(ty);
                 }
                 self.expr(field!(let_expr.init));
             },
@@ -451,11 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::Cast(expr, cast_ty) => {
                 bind!(self, expr, cast_ty);
                 kind!("Cast({expr}, {cast_ty})");
-                if let TyKind::Path(ref qpath) = cast_ty.value.kind {
-                    bind!(self, qpath);
-                    chain!(self, "let TyKind::Path(ref {qpath}) = {cast_ty}.kind");
-                    self.qpath(qpath);
-                }
+                self.maybe_path(cast_ty);
                 self.expr(expr);
             },
             ExprKind::Type(expr, _ty) => {
@@ -561,10 +598,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.expr(object);
                 self.expr(index);
             },
-            ExprKind::Path(ref qpath) => {
-                bind!(self, qpath);
-                kind!("Path(ref {qpath})");
-                self.qpath(qpath);
+            ExprKind::Path(_) => {
+                self.maybe_path(expr);
             },
             ExprKind::AddrOf(kind, mutability, inner) => {
                 bind!(self, inner);
@@ -608,7 +643,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                     StructTailExpr::None | StructTailExpr::DefaultFields(_) => None,
                 });
                 kind!("Struct({qpath}, {fields}, {base})");
-                self.qpath(qpath);
+                self.qpath(qpath, expr);
                 self.slice(fields, |field| {
                     self.ident(field!(field.ident));
                     self.expr(field!(field.expr));
@@ -648,7 +683,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         self.expr(expr);
     }
 
-    fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) {
+    fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>, pat: &Binding<&hir::Pat<'_>>) {
         let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
@@ -657,15 +692,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             PatExprKind::Lit { lit, negated } => {
                 bind!(self, lit);
                 bind!(self, negated);
-                kind!("Lit{{ref {lit}, {negated} }}");
+                kind!("Lit {{ ref {lit}, {negated} }}");
                 self.lit(lit);
             },
             PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
-            PatExprKind::Path(ref qpath) => {
-                bind!(self, qpath);
-                kind!("Path(ref {qpath})");
-                self.qpath(qpath);
-            },
+            PatExprKind::Path(_) => self.maybe_path(pat),
         }
     }
 
@@ -697,7 +728,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             PatKind::Struct(ref qpath, fields, ignore) => {
                 bind!(self, qpath, fields);
                 kind!("Struct(ref {qpath}, {fields}, {ignore})");
-                self.qpath(qpath);
+                self.qpath(qpath, pat);
                 self.slice(fields, |field| {
                     self.ident(field!(field.ident));
                     self.pat(field!(field.pat));
@@ -711,7 +742,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             PatKind::TupleStruct(ref qpath, fields, skip_pos) => {
                 bind!(self, qpath, fields);
                 kind!("TupleStruct(ref {qpath}, {fields}, {skip_pos:?})");
-                self.qpath(qpath);
+                self.qpath(qpath, pat);
                 self.slice(fields, |pat| self.pat(pat));
             },
             PatKind::Tuple(fields, skip_pos) => {
@@ -743,13 +774,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             PatKind::Expr(lit_expr) => {
                 bind!(self, lit_expr);
                 kind!("Expr({lit_expr})");
-                self.pat_expr(lit_expr);
+                self.pat_expr(lit_expr, pat);
             },
             PatKind::Range(start, end, end_kind) => {
                 opt_bind!(self, start, end);
                 kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
-                start.if_some(|e| self.pat_expr(e));
-                end.if_some(|e| self.pat_expr(e));
+                start.if_some(|e| self.pat_expr(e, pat));
+                end.if_some(|e| self.pat_expr(e, pat));
             },
             PatKind::Slice(start, middle, end) => {
                 bind!(self, start, end);
@@ -797,32 +828,3 @@ 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
 }
-
-fn path_to_string(path: &QPath<'_>) -> Result<String, ()> {
-    fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> {
-        match *path {
-            QPath::Resolved(_, path) => {
-                for (i, segment) in path.segments.iter().enumerate() {
-                    if i > 0 {
-                        *s += ", ";
-                    }
-                    write!(s, "{:?}", segment.ident.as_str()).unwrap();
-                }
-            },
-            QPath::TypeRelative(ty, segment) => match &ty.kind {
-                TyKind::Path(inner_path) => {
-                    inner(s, inner_path)?;
-                    *s += ", ";
-                    write!(s, "{:?}", segment.ident.as_str()).unwrap();
-                },
-                other => write!(s, "/* unimplemented: {other:?}*/").unwrap(),
-            },
-            QPath::LangItem(..) => return Err(()),
-        }
-
-        Ok(())
-    }
-    let mut s = String::new();
-    inner(&mut s, path)?;
-    Ok(s)
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 5b3f60ad6ab..45a5dbabeb4 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -154,7 +154,7 @@ impl LateLintPass<'_> for WildcardImports {
                 (span, false)
             };
 
-            let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord();
+            let mut imports: Vec<_> = used_imports.iter().map(ToString::to_string).collect();
             let imports_string = if imports.len() == 1 {
                 imports.pop().unwrap()
             } else if braced_glob {
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 11c14c14777..a8758b65c91 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,8 +1,8 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::is_in_test;
 use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node};
 use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
+use clippy_utils::{is_in_test, sym};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@@ -12,7 +12,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 }
 
 fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
-    let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else {
+    let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else {
         return;
     };
 
@@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
                     return;
                 };
 
-                if format_args.template.len() == 1 && last.as_str() == "\n" {
+                if format_args.template.len() == 1 && last == sym::LF {
                     // print!("\n"), write!(f, "\n")
 
                     diag.multipart_suggestion(
@@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
 }
 
 fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
-    if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..]
-        && literal.as_str() == "\n"
-    {
+    if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] {
         let mut span = format_args.span;
 
         let lint = if name == "writeln" {
@@ -500,9 +498,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
                     None => return,
                 },
                 LitKind::Char => (
-                    match lit.symbol.as_str() {
-                        "\"" => "\\\"",
-                        "\\'" => "'",
+                    match lit.symbol {
+                        sym::DOUBLE_QUOTE => "\\\"",
+                        sym::BACKSLASH_SINGLE_QUOTE => "'",
                         _ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) {
                             Some(stripped) => stripped,
                             None => return,
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 a97643e0eac..24b1381ba45 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
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty};
+use clippy_utils::ty::{is_type_diagnostic_item, ty_from_hir_ty};
 use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -54,8 +54,6 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             // 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()
-            // Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`.
-            && is_normalizable(cx, cx.param_env, ty)
             && let Ok(layout) = cx.layout_of(ty)
             && layout.is_zst()
         {
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 39c1aab8967..09f1084fe70 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
 use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
 use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
                     let mut vis = WaitFinder {
                         cx,
                         local_id,
+                        body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id),
                         state: VisitorState::WalkUpToLocal,
                         early_return: None,
                         missing_wait_branch: None,
@@ -129,6 +131,7 @@ struct MaybeWait(Span);
 struct WaitFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     local_id: HirId,
+    body_id: LocalDefId,
     state: VisitorState,
     early_return: Option<Span>,
     // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help
@@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
             }
         } else {
             match ex.kind {
-                ExprKind::Ret(e) => {
+                ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => {
                     visit_opt!(self, visit_expr, e);
                     if self.early_return.is_none() {
                         self.early_return = Some(ex.span);
diff --git a/src/tools/clippy/clippy_lints_internal/Cargo.toml b/src/tools/clippy/clippy_lints_internal/Cargo.toml
index 2a0ceac27a3..a8293a1ad39 100644
--- a/src/tools/clippy/clippy_lints_internal/Cargo.toml
+++ b/src/tools/clippy/clippy_lints_internal/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_lints_internal"
 version = "0.0.1"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 clippy_config = { path = "../clippy_config" }
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 d7967a0cc02..407deb45db0 100644
--- a/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
-use clippy_utils::{SpanlessEq, is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt};
+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};
@@ -10,6 +10,8 @@ use rustc_span::Span;
 
 use std::borrow::{Borrow, Cow};
 
+use crate::internal_paths;
+
 declare_tool_lint! {
     /// ### What it does
     /// Lints `span_lint_and_then` function calls, where the
@@ -80,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
         }
 
         if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind
-            && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"])
+            && internal_paths::SPAN_LINT_AND_THEN.matches_path(cx, func)
             && let ExprKind::Closure(&Closure { body, .. }) = call_f.kind
             && let body = cx.tcx.hir_body(body)
             && let only_expr = peel_blocks_with_stmt(body.value)
diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
new file mode 100644
index 00000000000..a1dacd359a0
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
@@ -0,0 +1,164 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::paths;
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::{AttrStyle, DelimArgs};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::{
+    AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_tool_lint! {
+    /// ### What it does
+    /// Checks for structs or enums that derive `serde::Deserialize` and that
+    /// do not have a `#[serde(deny_unknown_fields)]` attribute.
+    ///
+    /// ### Why is this bad?
+    /// If the struct or enum is used in [`clippy_config::conf::Conf`] and a
+    /// user inserts an unknown field by mistake, the user's error will be
+    /// silently ignored.
+    ///
+    /// ### Example
+    /// ```rust
+    /// #[derive(serde::Deserialize)]
+    /// pub struct DisallowedPath {
+    ///     path: String,
+    ///     reason: Option<String>,
+    ///     replacement: Option<String>,
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// #[derive(serde::Deserialize)]
+    /// #[serde(deny_unknown_fields)]
+    /// pub struct DisallowedPath {
+    ///     path: String,
+    ///     reason: Option<String>,
+    ///     replacement: Option<String>,
+    /// }
+    /// ```
+    pub clippy::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN,
+    Allow,
+    "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(DeriveDeserializeAllowingUnknown => [DERIVE_DESERIALIZE_ALLOWING_UNKNOWN]);
+
+impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        // Is this an `impl` (of a certain form)?
+        let ItemKind::Impl(Impl {
+            of_trait:
+                Some(TraitRef {
+                    path:
+                        Path {
+                            res: Res::Def(_, trait_def_id),
+                            ..
+                        },
+                    ..
+                }),
+            self_ty:
+                Ty {
+                    kind:
+                        TyKind::Path(QPath::Resolved(
+                            None,
+                            Path {
+                                res: Res::Def(_, self_ty_def_id),
+                                ..
+                            },
+                        )),
+                    ..
+                },
+            ..
+        }) = item.kind
+        else {
+            return;
+        };
+
+        // Is it an `impl` of the trait `serde::Deserialize`?
+        if !paths::SERDE_DESERIALIZE.get(cx).contains(trait_def_id) {
+            return;
+        }
+
+        // Is it derived?
+        if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) {
+            return;
+        }
+
+        // Is `self_ty` local?
+        let Some(local_def_id) = self_ty_def_id.as_local() else {
+            return;
+        };
+
+        // Does `self_ty` have a variant with named fields?
+        if !has_variant_with_named_fields(cx.tcx, local_def_id) {
+            return;
+        }
+
+        let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+
+        // Does `self_ty` have `#[serde(deny_unknown_fields)]`?
+        if let Some(tokens) = find_serde_attr_item(cx.tcx, hir_id)
+            && tokens.iter().any(is_deny_unknown_fields_token)
+        {
+            return;
+        }
+
+        span_lint(
+            cx,
+            DERIVE_DESERIALIZE_ALLOWING_UNKNOWN,
+            item.span,
+            "`#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`",
+        );
+    }
+}
+
+// Determines whether `def_id` corresponds to an ADT with at least one variant with named fields. A
+// variant has named fields if its `ctor` field is `None`.
+fn has_variant_with_named_fields(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let ty = tcx.type_of(def_id).skip_binder();
+
+    let rustc_middle::ty::Adt(adt_def, _) = ty.kind() else {
+        return false;
+    };
+
+    adt_def.variants().iter().any(|variant_def| variant_def.ctor.is_none())
+}
+
+fn find_serde_attr_item(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&TokenStream> {
+    tcx.hir_attrs(hir_id).iter().find_map(|attribute| {
+        if let Attribute::Unparsed(attr_item) = attribute
+            && let AttrItem {
+                path: AttrPath { segments, .. },
+                args: AttrArgs::Delimited(DelimArgs { tokens, .. }),
+                style: AttrStyle::Outer,
+                ..
+            } = &**attr_item
+            && segments.len() == 1
+            && segments[0].as_str() == "serde"
+        {
+            Some(tokens)
+        } else {
+            None
+        }
+    })
+}
+
+fn is_deny_unknown_fields_token(tt: &TokenTree) -> bool {
+    if let TokenTree::Token(token, _) = tt
+        && token
+            .ident()
+            .is_some_and(|(token, _)| token.as_str() == "deny_unknown_fields")
+    {
+        true
+    } else {
+        false
+    }
+}
diff --git a/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs b/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs
new file mode 100644
index 00000000000..dc1e30ab2bd
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs
@@ -0,0 +1,17 @@
+use clippy_utils::paths::{PathLookup, PathNS};
+use clippy_utils::{sym, type_path, value_path};
+
+// Paths inside rustc
+pub static EARLY_LINT_PASS: PathLookup = type_path!(rustc_lint::passes::EarlyLintPass);
+pub static KW_MODULE: PathLookup = type_path!(rustc_span::symbol::kw);
+pub static LINT: PathLookup = type_path!(rustc_lint_defs::Lint);
+pub static SYMBOL: PathLookup = type_path!(rustc_span::symbol::Symbol);
+pub static SYMBOL_AS_STR: PathLookup = value_path!(rustc_span::symbol::Symbol::as_str);
+pub static SYM_MODULE: PathLookup = type_path!(rustc_span::symbol::sym);
+pub static SYNTAX_CONTEXT: PathLookup = type_path!(rustc_span::hygiene::SyntaxContext);
+
+// Paths in clippy itself
+pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym);
+pub static MSRV_STACK: PathLookup = type_path!(clippy_utils::msrvs::MsrvStack);
+pub static PATH_LOOKUP_NEW: PathLookup = value_path!(clippy_utils::paths::PathLookup::new);
+pub static SPAN_LINT_AND_THEN: PathLookup = value_path!(clippy_utils::diagnostics::span_lint_and_then);
diff --git a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs b/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs
deleted file mode 100644
index 6cee3744234..00000000000
--- a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::match_type;
-use clippy_utils::{def_path_def_ids, paths};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Expr, ExprKind};
-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_span::sym;
-use rustc_span::symbol::Symbol;
-
-declare_tool_lint! {
-    /// ### What it does
-    /// Checks for interning string literals as symbols
-    ///
-    /// ### Why is this bad?
-    /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// let _ = Symbol::intern("f32");
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// let _ = sym::f32;
-    /// ```
-    pub clippy::INTERNING_LITERALS,
-    Warn,
-    "interning a symbol that is a literal",
-    report_in_external_macro: true
-}
-
-#[derive(Default)]
-pub struct InterningDefinedSymbol {
-    // Maps the symbol to the import path
-    symbol_map: FxHashMap<u32, (&'static str, Symbol)>,
-}
-
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]);
-
-impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        let modules = [
-            ("kw", &paths::KW_MODULE[..]),
-            ("sym", &paths::SYM_MODULE),
-            ("sym", &paths::CLIPPY_SYM_MODULE),
-        ];
-        for (prefix, module) in modules {
-            for def_id in def_path_def_ids(cx.tcx, module) {
-                // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will
-                // still lint but the suggestion will say to add it to `sym.rs` even if it's already there
-                if def_id.is_local() {
-                    continue;
-                }
-
-                for item in cx.tcx.module_children(def_id) {
-                    if let Res::Def(DefKind::Const, item_def_id) = item.res
-                        && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
-                        && match_type(cx, ty, &paths::SYMBOL)
-                        && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
-                        && let Some(value) = value.to_u32().discard_err()
-                    {
-                        self.symbol_map.insert(value, (prefix, item.ident.name));
-                    }
-                }
-            }
-        }
-    }
-
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Call(func, [arg]) = &expr.kind
-            && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
-            && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
-            && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
-        {
-            span_lint_and_then(
-                cx,
-                INTERNING_LITERALS,
-                expr.span,
-                "interning a string literal",
-                |diag| {
-                    let value = Symbol::intern(&arg).as_u32();
-                    let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) {
-                        ("use the preinterned symbol", format!("{prefix}::{name}"))
-                    } else {
-                        (
-                            "add the symbol to `clippy_utils/src/sym.rs` and use it",
-                            format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")),
-                        )
-                    };
-                    diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect);
-                },
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs b/src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs
deleted file mode 100644
index bee87efa3fc..00000000000
--- a/src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::def_path_res;
-use clippy_utils::diagnostics::span_lint;
-use rustc_hir as hir;
-use rustc_hir::Item;
-use rustc_hir::def::DefKind;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, FloatTy};
-use rustc_session::declare_lint_pass;
-use rustc_span::symbol::Symbol;
-
-declare_tool_lint! {
-    /// ### What it does
-    /// Checks the paths module for invalid paths.
-    ///
-    /// ### Why is this bad?
-    /// It indicates a bug in the code.
-    ///
-    /// ### Example
-    /// None.
-    pub clippy::INVALID_PATHS,
-    Warn,
-    "invalid path",
-    report_in_external_macro: true
-}
-
-declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
-
-impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let local_def_id = &cx.tcx.parent_module(item.hir_id());
-        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
-        if mod_name.as_str() == "paths"
-            && let hir::ItemKind::Const(.., body_id) = item.kind
-            && let Some(Constant::Vec(path)) = ConstEvalCtxt::with_env(
-                cx.tcx,
-                ty::TypingEnv::post_analysis(cx.tcx, item.owner_id),
-                cx.tcx.typeck(item.owner_id),
-            )
-            .eval_simple(cx.tcx.hir_body(body_id).value)
-            && let Some(path) = path
-                .iter()
-                .map(|x| {
-                    if let Constant::Str(s) = x {
-                        Some(s.as_str())
-                    } else {
-                        None
-                    }
-                })
-                .collect::<Option<Vec<&str>>>()
-            && !check_path(cx, &path[..])
-        {
-            span_lint(cx, INVALID_PATHS, item.span, "invalid path");
-        }
-    }
-}
-
-// This is not a complete resolver for paths. It works on all the paths currently used in the paths
-// module.  That's all it does and all it needs to do.
-pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-    if !def_path_res(cx.tcx, path).is_empty() {
-        return true;
-    }
-
-    // Some implementations can't be found by `path_to_res`, particularly inherent
-    // implementations of native types. Check lang items.
-    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
-    let lang_items = cx.tcx.lang_items();
-    // This list isn't complete, but good enough for our current list of paths.
-    let incoherent_impls = [
-        SimplifiedType::Float(FloatTy::F32),
-        SimplifiedType::Float(FloatTy::F64),
-        SimplifiedType::Slice,
-        SimplifiedType::Str,
-        SimplifiedType::Bool,
-        SimplifiedType::Char,
-    ]
-    .iter()
-    .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
-    .copied();
-    for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
-        let lang_item_path = cx.get_def_path(item_def_id);
-        if path_syms.starts_with(&lang_item_path)
-            && let [item] = &path_syms[lang_item_path.len()..]
-        {
-            if matches!(
-                cx.tcx.def_kind(item_def_id),
-                DefKind::Mod | DefKind::Enum | DefKind::Trait
-            ) {
-                for child in cx.tcx.module_children(item_def_id) {
-                    if child.ident.name == *item {
-                        return true;
-                    }
-                }
-            } else {
-                for child in cx.tcx.associated_item_def_ids(item_def_id) {
-                    if cx.tcx.item_name(*child) == *item {
-                        return true;
-                    }
-                }
-            }
-        }
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs
index 1c42f4112f9..0c94d100c41 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lib.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs
@@ -1,7 +1,8 @@
-#![feature(let_chains, rustc_private)]
+#![feature(rustc_private)]
 #![allow(
     clippy::missing_docs_in_private_items,
     clippy::must_use_candidate,
+    clippy::symbol_as_str,
     rustc::diagnostic_outside_of_impl,
     rustc::untranslatable_diagnostic
 )]
@@ -19,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;
@@ -31,12 +33,13 @@ extern crate rustc_span;
 
 mod almost_standard_lint_formulation;
 mod collapsible_calls;
-mod interning_literals;
-mod invalid_paths;
+mod derive_deserialize_allowing_unknown;
+mod internal_paths;
 mod lint_without_lint_pass;
 mod msrv_attr_impl;
 mod outer_expn_data_pass;
 mod produce_ice;
+mod symbols;
 mod unnecessary_def_path;
 mod unsorted_clippy_utils_paths;
 
@@ -45,8 +48,7 @@ use rustc_lint::{Lint, LintStore};
 static LINTS: &[&Lint] = &[
     almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION,
     collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
-    interning_literals::INTERNING_LITERALS,
-    invalid_paths::INVALID_PATHS,
+    derive_deserialize_allowing_unknown::DERIVE_DESERIALIZE_ALLOWING_UNKNOWN,
     lint_without_lint_pass::DEFAULT_LINT,
     lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
     lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
@@ -54,6 +56,8 @@ static LINTS: &[&Lint] = &[
     msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
     outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
     produce_ice::PRODUCE_ICE,
+    symbols::INTERNING_LITERALS,
+    symbols::SYMBOL_AS_STR,
     unnecessary_def_path::UNNECESSARY_DEF_PATH,
     unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
 ];
@@ -64,10 +68,10 @@ pub fn register_lints(store: &mut LintStore) {
     store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths));
     store.register_early_pass(|| Box::new(produce_ice::ProduceIce));
     store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls));
-    store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths));
-    store.register_late_pass(|_| Box::<interning_literals::InterningDefinedSymbol>::default());
+    store.register_late_pass(|_| Box::new(derive_deserialize_allowing_unknown::DeriveDeserializeAllowingUnknown));
+    store.register_late_pass(|_| Box::<symbols::Symbols>::default());
     store.register_late_pass(|_| Box::<lint_without_lint_pass::LintWithoutLintPass>::default());
-    store.register_late_pass(|_| Box::<unnecessary_def_path::UnnecessaryDefPath>::default());
+    store.register_late_pass(|_| Box::new(unnecessary_def_path::UnnecessaryDefPath));
     store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));
     store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl));
     store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new()));
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 6a75defcce3..655d8fb8d1b 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
@@ -1,6 +1,7 @@
+use crate::internal_paths;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::{is_lint_allowed, match_def_path, paths};
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_hir as hir;
@@ -209,10 +210,10 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
         && let TyKind::Path(ref path) = inner.kind
         && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id)
     {
-        return match_def_path(cx, def_id, &paths::LINT);
+        internal_paths::LINT.matches(cx, def_id)
+    } else {
+        false
     }
-
-    false
 }
 
 fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
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 dda054546e2..d48d8dc57b2 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
@@ -1,7 +1,6 @@
+use crate::internal_paths;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::match_type;
-use clippy_utils::{match_def_path, paths};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -31,7 +30,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
                 .tcx
                 .impl_trait_ref(item.owner_id)
                 .map(EarlyBinder::instantiate_identity)
-            && match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS)
+            && internal_paths::EARLY_LINT_PASS.matches(cx, trait_ref.def_id)
             && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind()
             && self_ty_def.is_struct()
             && self_ty_def.all_fields().any(|f| {
@@ -40,7 +39,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
                     .instantiate_identity()
                     .walk()
                     .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
-                    .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV_STACK))
+                    .any(|t| internal_paths::MSRV_STACK.matches_ty(cx, t.expect_ty()))
             })
             && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes")
         {
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 e9441964797..40951443a48 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,6 +1,6 @@
+use crate::internal_paths;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::match_type;
-use clippy_utils::{is_lint_allowed, method_calls, paths};
+use clippy_utils::{is_lint_allowed, method_calls};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
             && let (self_arg, args) = arg_lists[1]
             && args.is_empty()
             && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
-            && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT)
+            && internal_paths::SYNTAX_CONTEXT.matches_ty(cx, self_ty)
         {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints_internal/src/symbols.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
new file mode 100644
index 00000000000..5aee545fb0f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
@@ -0,0 +1,207 @@
+use crate::internal_paths;
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::LitKind;
+use rustc_data_structures::fx::FxHashMap;
+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_span::symbol::Symbol;
+use rustc_span::{Span, sym};
+
+declare_tool_lint! {
+    /// ### What it does
+    /// Checks for interning string literals as symbols
+    ///
+    /// ### Why is this bad?
+    /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _ = Symbol::intern("f32");
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// let _ = sym::f32;
+    /// ```
+    pub clippy::INTERNING_LITERALS,
+    Warn,
+    "interning a symbol that is a literal",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    /// ### What it does
+    /// Checks for calls to `Symbol::as_str`
+    ///
+    /// ### Why is this bad?
+    /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// symbol.as_str() == "foo"
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// symbol == sym::foo
+    /// ```
+    pub clippy::SYMBOL_AS_STR,
+    Warn,
+    "calls to `Symbol::as_str`",
+    report_in_external_macro: true
+}
+
+#[derive(Default)]
+pub struct Symbols {
+    // Maps the symbol to the import path
+    symbol_map: FxHashMap<u32, (&'static str, Symbol)>,
+}
+
+impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]);
+
+impl Symbols {
+    fn lit_suggestion(&self, lit: &Lit) -> Option<(Span, String)> {
+        if let LitKind::Str(name, _) = lit.node {
+            let sugg = if let Some((prefix, name)) = self.symbol_map.get(&name.as_u32()) {
+                format!("{prefix}::{name}")
+            } else {
+                format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_"))
+            };
+            Some((lit.span, sugg))
+        } else {
+            None
+        }
+    }
+
+    fn expr_suggestion(&self, expr: &Expr<'_>) -> Option<(Span, String)> {
+        if let ExprKind::Lit(lit) = expr.kind {
+            self.lit_suggestion(lit)
+        } else {
+            None
+        }
+    }
+
+    fn pat_suggestions(&self, pat: &Pat<'_>, suggestions: &mut Vec<(Span, String)>) {
+        pat.walk_always(|pat| {
+            if let PatKind::Expr(pat_expr) = pat.kind
+                && let PatExprKind::Lit { lit, .. } = pat_expr.kind
+            {
+                suggestions.extend(self.lit_suggestion(lit));
+            }
+        });
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for Symbols {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        let modules = [
+            ("kw", &internal_paths::KW_MODULE),
+            ("sym", &internal_paths::SYM_MODULE),
+            ("sym", &internal_paths::CLIPPY_SYM_MODULE),
+        ];
+        for (prefix, module) in modules {
+            for def_id in module.get(cx) {
+                // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will
+                // still lint but the suggestion may suggest the incorrect name for symbols such as `sym::CRLF`
+                if def_id.is_local() {
+                    continue;
+                }
+
+                for item in cx.tcx.module_children(def_id) {
+                    if let Res::Def(DefKind::Const, item_def_id) = item.res
+                        && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
+                        && internal_paths::SYMBOL.matches_ty(cx, ty)
+                        && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
+                        && let Some(value) = value.to_u32().discard_err()
+                    {
+                        self.symbol_map.insert(value, (prefix, item.ident.name));
+                    }
+                }
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Call(func, [arg]) = &expr.kind
+            && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
+            && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
+            && let Some((_, sugg)) = self.expr_suggestion(arg)
+        {
+            span_lint_and_then(
+                cx,
+                INTERNING_LITERALS,
+                expr.span,
+                "interning a string literal",
+                |diag| {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "use a preinterned symbol instead",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.help("add the symbol to `clippy_utils/src/sym.rs` if needed");
+                },
+            );
+        }
+
+        if let Some(as_str) = as_str_span(cx, expr)
+            && let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
+        {
+            let mut suggestions = Vec::new();
+
+            match parent.kind {
+                ExprKind::Binary(_, lhs, rhs) => {
+                    suggestions.extend(self.expr_suggestion(lhs));
+                    suggestions.extend(self.expr_suggestion(rhs));
+                },
+                ExprKind::Match(_, arms, _) => {
+                    for arm in arms {
+                        self.pat_suggestions(arm.pat, &mut suggestions);
+                    }
+                },
+                _ => {},
+            }
+
+            if suggestions.is_empty() {
+                return;
+            }
+
+            span_lint_and_then(
+                cx,
+                SYMBOL_AS_STR,
+                expr.span,
+                "converting a Symbol to a string",
+                |diag| {
+                    suggestions.push((as_str, String::new()));
+                    diag.multipart_suggestion(
+                        "use preinterned symbols instead",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.help("add the symbols to `clippy_utils/src/sym.rs` if needed");
+                },
+            );
+        }
+    }
+}
+
+/// ```ignore
+/// symbol.as_str()
+/// //     ^^^^^^^^
+/// ```
+fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
+    if let ExprKind::MethodCall(_, recv, [], _) = expr.kind
+        && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+        && internal_paths::SYMBOL_AS_STR.matches(cx, method_def_id)
+    {
+        Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi()))
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
index 6bdfbed55b0..8877f1faf0e 100644
--- a/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
@@ -1,23 +1,14 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
-use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
+use crate::internal_paths;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::{PathNS, lookup_path};
+use clippy_utils::{path_def_id, peel_ref_operators};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
+use rustc_lint_defs::{declare_lint_pass, declare_tool_lint};
 use rustc_middle::mir::ConstValue;
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc};
-use rustc_middle::ty::{self, Ty};
-use rustc_session::impl_lint_pass;
-use rustc_span::Span;
 use rustc_span::symbol::Symbol;
 
-use std::str;
-
 declare_tool_lint! {
     /// ### What it does
     /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used.
@@ -28,12 +19,14 @@ declare_tool_lint! {
     ///
     /// ### Example
     /// ```rust,ignore
-    /// utils::match_type(cx, ty, &paths::VEC)
+    /// pub static VEC: PathLookup = path!(alloc::vec::Vec);
+    ///
+    /// VEC.contains_ty(cx, ty)
     /// ```
     ///
     /// Use instead:
     /// ```rust,ignore
-    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
+    /// is_type_diagnostic_item(cx, ty, sym::Vec)
     /// ```
     pub clippy::UNNECESSARY_DEF_PATH,
     Warn,
@@ -41,259 +34,67 @@ declare_tool_lint! {
     report_in_external_macro: true
 }
 
-impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
-
-#[derive(Default)]
-pub struct UnnecessaryDefPath {
-    array_def_ids: FxIndexSet<(DefId, Span)>,
-    linted_def_ids: FxHashSet<DefId>,
-}
+declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
-            return;
-        }
-
-        match expr.kind {
-            ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span),
-            ExprKind::Array(elements) => self.check_array(cx, elements, expr.span),
-            _ => {},
-        }
-    }
-
-    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
-        for &(def_id, span) in &self.array_def_ids {
-            if self.linted_def_ids.contains(&def_id) {
-                continue;
-            }
-
-            let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) {
-                ("diagnostic item", format!("sym::{sym}"))
-            } else if let Some(sym) = get_lang_item_name(cx, def_id) {
-                ("language item", format!("LangItem::{sym}"))
-            } else {
-                continue;
-            };
-
-            span_lint_and_help(
-                cx,
-                UNNECESSARY_DEF_PATH,
-                span,
-                format!("hardcoded path to a {msg}"),
-                None,
-                format!("convert all references to use `{sugg}`"),
-            );
-        }
-    }
-}
-
-impl UnnecessaryDefPath {
-    #[allow(clippy::too_many_lines)]
-    fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) {
-        enum Item {
-            LangItem(&'static str),
-            DiagnosticItem(Symbol),
-        }
-        static PATHS: &[&[&str]] = &[
-            &["clippy_utils", "match_def_path"],
-            &["clippy_utils", "match_trait_method"],
-            &["clippy_utils", "ty", "match_type"],
-            &["clippy_utils", "is_expr_path_def_path"],
-        ];
-
-        if let [cx_arg, def_arg, args @ ..] = args
-            && let ExprKind::Path(path) = &func.kind
-            && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id()
-            && let Some(which_path) = match_any_def_paths(cx, id, PATHS)
-            && let item_arg = if which_path == 4 { &args[1] } else { &args[0] }
-            // Extract the path to the matched type
-            && let Some(segments) = path_to_matched_type(cx, item_arg)
-            && let segments = segments.iter().map(|sym| &**sym).collect::<Vec<_>>()
-            && let Some(def_id) = def_path_def_ids(cx.tcx, &segments[..]).next()
+        if let ExprKind::Call(ctor, [_, path]) = expr.kind
+            && internal_paths::PATH_LOOKUP_NEW.matches_path(cx, ctor)
+            && let ExprKind::Array(segments) = peel_ref_operators(cx, path).kind
+            && let Some(macro_id) = expr.span.ctxt().outer_expn_data().macro_def_id
         {
-            // Check if the target item is a diagnostic item or LangItem.
-            #[rustfmt::skip]
-            let (msg, item) = if let Some(item_name)
-                = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
-            {
-                (
-                    "use of a def path to a diagnostic item",
-                    Item::DiagnosticItem(*item_name),
-                )
-            } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
-                (
-                    "use of a def path to a `LangItem`",
-                    Item::LangItem(item_name),
-                )
-            } else {
-                return;
-            };
-
-            let has_ctor = match cx.tcx.def_kind(def_id) {
-                DefKind::Struct => {
-                    let variant = cx.tcx.adt_def(def_id).non_enum_variant();
-                    variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
-                },
-                DefKind::Variant => {
-                    let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
-                    variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
-                },
-                _ => false,
+            let ns = match cx.tcx.item_name(macro_id).as_str() {
+                "type_path" => PathNS::Type,
+                "value_path" => PathNS::Value,
+                "macro_path" => PathNS::Macro,
+                _ => unreachable!(),
             };
 
-            let mut app = Applicability::MachineApplicable;
-            let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
-            let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
-            let (sugg, with_note) = match (which_path, item) {
-                // match_def_path
-                (0, Item::DiagnosticItem(item)) => (
-                    format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"),
-                    has_ctor,
-                ),
-                (0, Item::LangItem(item)) => (
-                    format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"),
-                    has_ctor,
-                ),
-                // match_trait_method
-                (1, Item::DiagnosticItem(item)) => {
-                    (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false)
-                },
-                // match_type
-                (2, Item::DiagnosticItem(item)) => (
-                    format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
-                    false,
-                ),
-                (2, Item::LangItem(item)) => (
-                    format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"),
-                    false,
-                ),
-                // is_expr_path_def_path
-                (3, Item::DiagnosticItem(item)) if has_ctor => (
-                    format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",),
-                    false,
-                ),
-                (3, Item::LangItem(item)) if has_ctor => (
-                    format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",),
-                    false,
-                ),
-                (3, Item::DiagnosticItem(item)) => (
-                    format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
-                    false,
-                ),
-                (3, Item::LangItem(item)) => (
-                    format!(
-                        "path_res({cx_snip}, {def_snip}).opt_def_id()\
-                            .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))",
-                    ),
-                    false,
-                ),
-                _ => return,
-            };
-
-            span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| {
-                diag.span_suggestion(span, "try", sugg, app);
-                if with_note {
-                    diag.help(
-                        "if this `DefId` came from a constructor expression or pattern then the \
-                                parent `DefId` should be used instead",
+            let path: Vec<Symbol> = segments
+                .iter()
+                .map(|segment| {
+                    if let Some(const_def_id) = path_def_id(cx, segment)
+                        && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(const_def_id)
+                        && let Some(value) = value.to_u32().discard_err()
+                    {
+                        Symbol::new(value)
+                    } else {
+                        panic!("failed to resolve path {:?}", expr.span);
+                    }
+                })
+                .collect();
+
+            for def_id in lookup_path(cx.tcx, ns, &path) {
+                if let Some(name) = cx.tcx.get_diagnostic_name(def_id) {
+                    span_lint_and_then(
+                        cx,
+                        UNNECESSARY_DEF_PATH,
+                        expr.span.source_callsite(),
+                        format!("a diagnostic name exists for this path: sym::{name}"),
+                        |diag| {
+                            diag.help(
+                                "remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead",
+                            );
+                            diag.help("see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils");
+                        },
+                    );
+                } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
+                    span_lint_and_then(
+                        cx,
+                        UNNECESSARY_DEF_PATH,
+                        expr.span.source_callsite(),
+                        format!("a language item exists for this path: LangItem::{item_name}"),
+                        |diag| {
+                            diag.help("remove the `PathLookup` and use utilities such as `cx.tcx.lang_items` instead");
+                            diag.help("see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=lang&filter-crate=clippy_utils");
+                        },
                     );
                 }
-            });
-
-            self.linted_def_ids.insert(def_id);
-        }
-    }
-
-    fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
-        let Some(path) = path_from_array(elements) else { return };
-
-        for def_id in def_path_def_ids(cx.tcx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
-            self.array_def_ids.insert((def_id, span));
-        }
-    }
-}
-
-fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Vec<String>> {
-    match peel_hir_expr_refs(expr).0.kind {
-        ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
-            Res::Local(hir_id) => {
-                if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
-                    path_to_matched_type(cx, init)
-                } else {
-                    None
-                }
-            },
-            Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path(
-                cx,
-                cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
-                cx.tcx.type_of(def_id).instantiate_identity(),
-            ),
-            Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
-                ConstValue::Indirect { alloc_id, offset } if offset.bytes() == 0 => {
-                    let alloc = cx.tcx.global_alloc(alloc_id).unwrap_memory();
-                    read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity())
-                },
-                _ => None,
-            },
-            _ => None,
-        },
-        ExprKind::Array(exprs) => path_from_array(exprs),
-        _ => None,
-    }
-}
-
-fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
-    let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
-        let &alloc = alloc.provenance().ptrs().values().next()?;
-        if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
-            (alloc.inner(), ty)
-        } else {
-            return None;
+            }
         }
-    } else {
-        (alloc, ty)
-    };
-
-    if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind()
-        && let ty::Ref(_, ty, Mutability::Not) = *ty.kind()
-        && ty.is_str()
-    {
-        alloc
-            .provenance()
-            .ptrs()
-            .values()
-            .map(|&alloc| {
-                if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
-                    let alloc = alloc.inner();
-                    str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
-                        .ok()
-                        .map(ToOwned::to_owned)
-                } else {
-                    None
-                }
-            })
-            .collect()
-    } else {
-        None
     }
 }
 
-fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
-    exprs
-        .iter()
-        .map(|expr| {
-            if let ExprKind::Lit(lit) = &expr.kind
-                && let LitKind::Str(sym, _) = lit.node
-            {
-                return Some((*sym.as_str()).to_owned());
-            }
-
-            None
-        })
-        .collect()
-}
-
 fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
     if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) {
         Some(lang_item.variant_name())
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index b98e9901750..ac970e1c4b0 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_utils"
 # begin autogenerated version
-version = "0.1.88"
+version = "0.1.89"
 # end autogenerated version
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index aceff14a159..d4080d06d3c 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-04-22
+nightly-2025-05-14
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index d4e66ebd8e1..dbb99348290 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -3,14 +3,14 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::consts::{ConstEvalCtxt, Constant};
-use crate::is_expn_of;
 use crate::ty::is_type_diagnostic_item;
+use crate::{is_expn_of, sym};
 
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr};
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym, symbol};
+use rustc_span::{Span, symbol};
 
 /// The essential nodes of a desugared for loop as well as the entire span:
 /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
@@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                     return Some(VecInitKind::New);
                 } else if name.ident.name == symbol::kw::Default {
                     return Some(VecInitKind::Default);
-                } else if name.ident.name.as_str() == "with_capacity" {
+                } else if name.ident.name == sym::with_capacity {
                     let arg = args.first()?;
                     return match ConstEvalCtxt::new(cx).eval_simple(arg) {
                         Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 17368a7530d..c37231d0931 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1118,8 +1118,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_const_arg(e);
             },
             TyPatKind::Or(variants) => {
-                for variant in variants.iter() {
-                    self.hash_ty_pat(variant)
+                for variant in variants {
+                    self.hash_ty_pat(variant);
                 }
             },
             TyPatKind::Err(_) => {},
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 264b9b0406d..4fb608a6482 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,9 +1,6 @@
-#![feature(array_chunks)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
-#![feature(macro_metavar_expr_concat)]
 #![feature(macro_metavar_expr)]
-#![feature(let_chains)]
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(assert_matches)]
@@ -30,6 +27,7 @@
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 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;
@@ -91,34 +89,34 @@ 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_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::definitions::{DefPath, DefPathData};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
 use rustc_hir::{
-    self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
-    CoroutineDesugaring, CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg,
-    GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource,
-    Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath,
-    Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
+    self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring,
+    CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl,
+    ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
+    Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
+    TraitItemKind, TraitRef, TyKind, UnOp, def,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty,
-    TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,
+    TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -131,7 +129,6 @@ use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
 use crate::higher::Range;
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr_without_closures;
-use rustc_middle::hir::nested_filter;
 
 #[macro_export]
 macro_rules! extract_msrv_attr {
@@ -239,7 +236,7 @@ pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
 ///  * const blocks (or inline consts)
 ///  * associated constants
 pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
-    use ConstContext::{Const, ConstFn, Static};
+    use rustc_hir::ConstContext::{Const, ConstFn, Static};
     let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else {
         return false;
     };
@@ -347,14 +344,6 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
     }
 }
 
-/// Checks if the method call given in `expr` belongs to the given trait.
-/// This is a deprecated function, consider using [`is_trait_method`].
-pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
-    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-    let trt_id = cx.tcx.trait_of_item(def_id);
-    trt_id.is_some_and(|trt_id| match_def_path(cx, trt_id, path))
-}
-
 /// Checks if the given method call expression calls an inherent method.
 pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
@@ -438,44 +427,6 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
         })
 }
 
-/// THIS METHOD IS DEPRECATED. Matches a `QPath` against a slice of segment string literals.
-///
-/// This method is deprecated and will eventually be removed since it does not match against the
-/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
-/// `QPath::Resolved.1.res.opt_def_id()`.
-///
-/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
-/// `rustc_hir::QPath`.
-///
-/// # Examples
-/// ```rust,ignore
-/// match_qpath(path, &["std", "rt", "begin_unwind"])
-/// ```
-pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
-    match *path {
-        QPath::Resolved(_, path) => match_path(path, segments),
-        QPath::TypeRelative(ty, segment) => match ty.kind {
-            TyKind::Path(ref inner_path) => {
-                if let [prefix @ .., end] = segments
-                    && match_qpath(inner_path, prefix)
-                {
-                    return segment.ident.name.as_str() == *end;
-                }
-                false
-            },
-            _ => false,
-        },
-        QPath::LangItem(..) => false,
-    }
-}
-
-/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
-///
-/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
-pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
-    path_def_id(cx, expr).is_some_and(|id| match_def_path(cx, id, segments))
-}
-
 /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
 /// it matches the given lang item.
 pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool {
@@ -492,34 +443,6 @@ pub fn is_path_diagnostic_item<'tcx>(
     path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id))
 }
 
-/// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals.
-///
-/// This method is deprecated and will eventually be removed since it does not match against the
-/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
-/// `QPath::Resolved.1.res.opt_def_id()`.
-///
-/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
-/// `rustc_hir::Path`.
-///
-/// # Examples
-///
-/// ```rust,ignore
-/// if match_path(&trait_ref.path, &paths::HASH) {
-///     // This is the `std::hash::Hash` trait.
-/// }
-///
-/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
-///     // This is a `rustc_middle::lint::Lint`.
-/// }
-/// ```
-pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
-    path.segments
-        .iter()
-        .rev()
-        .zip(segments.iter().rev())
-        .all(|(a, b)| a.ident.name.as_str() == *b)
-}
-
 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
     if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind
@@ -586,201 +509,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
     path_res(cx, maybe_path).opt_def_id()
 }
 
-fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
-    let ty = match name {
-        "bool" => SimplifiedType::Bool,
-        "char" => SimplifiedType::Char,
-        "str" => SimplifiedType::Str,
-        "array" => SimplifiedType::Array,
-        "slice" => SimplifiedType::Slice,
-        // FIXME: rustdoc documents these two using just `pointer`.
-        //
-        // Maybe this is something we should do here too.
-        "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
-        "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
-        "isize" => SimplifiedType::Int(IntTy::Isize),
-        "i8" => SimplifiedType::Int(IntTy::I8),
-        "i16" => SimplifiedType::Int(IntTy::I16),
-        "i32" => SimplifiedType::Int(IntTy::I32),
-        "i64" => SimplifiedType::Int(IntTy::I64),
-        "i128" => SimplifiedType::Int(IntTy::I128),
-        "usize" => SimplifiedType::Uint(UintTy::Usize),
-        "u8" => SimplifiedType::Uint(UintTy::U8),
-        "u16" => SimplifiedType::Uint(UintTy::U16),
-        "u32" => SimplifiedType::Uint(UintTy::U32),
-        "u64" => SimplifiedType::Uint(UintTy::U64),
-        "u128" => SimplifiedType::Uint(UintTy::U128),
-        "f32" => SimplifiedType::Float(FloatTy::F32),
-        "f64" => SimplifiedType::Float(FloatTy::F64),
-        _ => {
-            return [].iter().copied();
-        },
-    };
-
-    tcx.incoherent_impls(ty).iter().copied()
-}
-
-fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
-    match tcx.def_kind(def_id) {
-        DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
-            .module_children(def_id)
-            .iter()
-            .filter(|item| item.ident.name == name)
-            .map(|child| child.res.expect_non_local())
-            .collect(),
-        DefKind::Impl { .. } => tcx
-            .associated_item_def_ids(def_id)
-            .iter()
-            .copied()
-            .filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
-            .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
-            .collect(),
-        _ => Vec::new(),
-    }
-}
-
-fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
-    let root_mod;
-    let item_kind = match tcx.hir_node_by_def_id(local_id) {
-        Node::Crate(r#mod) => {
-            root_mod = ItemKind::Mod(Ident::dummy(), r#mod);
-            &root_mod
-        },
-        Node::Item(item) => &item.kind,
-        _ => return Vec::new(),
-    };
-
-    let res = |ident: Ident, owner_id: OwnerId| {
-        if ident.name == name {
-            let def_id = owner_id.to_def_id();
-            Some(Res::Def(tcx.def_kind(def_id), def_id))
-        } else {
-            None
-        }
-    };
-
-    match item_kind {
-        ItemKind::Mod(_, r#mod) => r#mod
-            .item_ids
-            .iter()
-            .filter_map(|&item_id| {
-                let ident = tcx.hir_item(item_id).kind.ident()?;
-                res(ident, item_id.owner_id)
-            })
-            .collect(),
-        ItemKind::Impl(r#impl) => r#impl
-            .items
-            .iter()
-            .filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id))
-            .collect(),
-        ItemKind::Trait(.., trait_item_refs) => trait_item_refs
-            .iter()
-            .filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id))
-            .collect(),
-        _ => Vec::new(),
-    }
-}
-
-fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
-    if let Some(local_id) = def_id.as_local() {
-        local_item_children_by_name(tcx, local_id, name)
-    } else {
-        non_local_item_children_by_name(tcx, def_id, name)
-    }
-}
-
-/// Finds the crates called `name`, may be multiple due to multiple major versions.
-pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> Vec<Res> {
-    tcx.crates(())
-        .iter()
-        .copied()
-        .filter(move |&num| tcx.crate_name(num) == name)
-        .map(CrateNum::as_def_id)
-        .map(|id| Res::Def(tcx.def_kind(id), id))
-        .collect()
-}
-
-/// Resolves a def path like `std::vec::Vec`.
-///
-/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
-/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
-///
-/// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec`
-/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
-///
-/// This function is expensive and should be used sparingly.
-pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec<Res> {
-    let (base, path) = match path {
-        [primitive] => {
-            return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
-        },
-        [base, path @ ..] => (base, path),
-        _ => return Vec::new(),
-    };
-
-    let base_sym = Symbol::intern(base);
-
-    let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
-        Some(LOCAL_CRATE.as_def_id())
-    } else {
-        None
-    };
-
-    let crates = find_primitive_impls(tcx, base)
-        .chain(local_crate)
-        .map(|id| Res::Def(tcx.def_kind(id), id))
-        .chain(find_crates(tcx, base_sym))
-        .collect();
-
-    def_path_res_with_base(tcx, crates, path)
-}
-
-/// Resolves a def path like `vec::Vec` with the base `std`.
-///
-/// This is lighter than [`def_path_res`], and should be called with [`find_crates`] looking up
-/// items from the same crate repeatedly, although should still be used sparingly.
-pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec<Res>, mut path: &[&str]) -> Vec<Res> {
-    while let [segment, rest @ ..] = path {
-        path = rest;
-        let segment = Symbol::intern(segment);
-
-        base = base
-            .into_iter()
-            .filter_map(|res| res.opt_def_id())
-            .flat_map(|def_id| {
-                // When the current def_id is e.g. `struct S`, check the impl items in
-                // `impl S { ... }`
-                let inherent_impl_children = tcx
-                    .inherent_impls(def_id)
-                    .iter()
-                    .flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
-
-                let direct_children = item_children_by_name(tcx, def_id, segment);
-
-                inherent_impl_children.chain(direct_children)
-            })
-            .collect();
-    }
-
-    base
-}
-
-/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
-pub fn def_path_def_ids(tcx: TyCtxt<'_>, path: &[&str]) -> impl Iterator<Item = DefId> + use<> {
-    def_path_res(tcx, path).into_iter().filter_map(|res| res.opt_def_id())
-}
-
-/// Convenience function to get the `DefId` of a trait by path.
-/// It could be a trait or trait alias.
-///
-/// This function is expensive and should be used sparingly.
-pub fn get_trait_def_id(tcx: TyCtxt<'_>, path: &[&str]) -> Option<DefId> {
-    def_path_res(tcx, path).into_iter().find_map(|res| match res {
-        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
-        _ => None,
-    })
-}
-
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 ///
 /// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
@@ -1412,7 +1140,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 }
 
 /// Gets the name of the item the expression is in, if available.
-pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
+pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id;
     match cx.tcx.hir_node_by_def_id(parent_id) {
         Node::Item(item) => item.kind.ident().map(|ident| ident.name),
@@ -2065,30 +1793,12 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
         })
 }
 
-/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
-/// any.
-///
-/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
-pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
-    let search_path = cx.get_def_path(did);
-    paths
-        .iter()
-        .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
-}
-
-/// Checks if the given `DefId` matches the path.
-pub fn match_def_path(cx: &LateContext<'_>, did: DefId, syms: &[&str]) -> bool {
-    // We should probably move to Symbols in Clippy as well rather than interning every time.
-    let path = cx.get_def_path(did);
-    syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
-}
-
 /// Checks if the given `DefId` matches the `libc` item.
 pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> 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.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name)
+    path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name)
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -3101,7 +2811,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
     sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
 }
 
-/// Returns whether the given let pattern and else body can be turned into a question mark
+/// Returns whether the given let pattern and else body can be turned into the `?` operator
 ///
 /// For this example:
 /// ```ignore
@@ -3124,8 +2834,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
 /// ```
 ///
 /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
-/// the question mark operator is applicable here. Callers have to check whether we are in a
-/// constant or not.
+/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not.
 pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
     cx: &LateContext<'_>,
     pat: &'a Pat<'hir>,
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 19061b574ff..599c6f3a4ff 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;
@@ -22,7 +23,8 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
-    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT }
+    1,88,0 { LET_CHAINS }
+    1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
     1,85,0 { UINT_FLOAT_MIDPOINT }
     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 }
@@ -38,7 +40,7 @@ msrv_aliases! {
     1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
-    1,63,0 { CLONE_INTO }
+    1,63,0 { CLONE_INTO, CONST_SLICE_FROM_REF }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
     1,60,0 { ABS_DIFF }
     1,59,0 { THREAD_LOCAL_CONST_INIT }
@@ -68,7 +70,7 @@ msrv_aliases! {
     1,31,0 { OPTION_REPLACE }
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,29,0 { ITER_FLATTEN }
-    1,28,0 { FROM_BOOL, REPEAT_WITH }
+    1,28,0 { FROM_BOOL, REPEAT_WITH, SLICE_FROM_REF }
     1,27,0 { ITERATOR_TRY_FOLD }
     1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
     1,24,0 { IS_ASCII_DIGIT }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 7f64ebd3b64..e5179e479cc 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -4,62 +4,343 @@
 //! Whenever possible, please consider diagnostic items over hardcoded paths.
 //! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 
-// Paths inside rustc
-pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
-pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
-    ["rustc_lint_defs", "Applicability", "Unspecified"],
-    ["rustc_lint_defs", "Applicability", "HasPlaceholders"],
-    ["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
-    ["rustc_lint_defs", "Applicability", "MachineApplicable"],
-];
-pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"];
-pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
-pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
-pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
-pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
-pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
-pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
-pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
-pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
-pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
-pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
-pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
-pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
+use crate::{MaybePath, path_def_id, sym};
+use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS};
+use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
+use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, TraitItemRef, UseKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::{FloatTy, IntTy, Ty, TyCtxt, UintTy};
+use rustc_span::{Ident, STDLIB_STABLE_CRATES, Symbol};
+use std::sync::OnceLock;
 
-// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
-pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
-pub const IO_ERROR_NEW: [&str; 5] = ["std", "io", "error", "Error", "new"];
-pub const IO_ERRORKIND_OTHER: [&str; 5] = ["std", "io", "error", "ErrorKind", "Other"];
-pub const ALIGN_OF: [&str; 3] = ["core", "mem", "align_of"];
+/// Specifies whether to resolve a path in the [`TypeNS`], [`ValueNS`], [`MacroNS`] or in an
+/// arbitrary namespace
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum PathNS {
+    Type,
+    Value,
+    Macro,
+
+    /// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return
+    /// either the macro or the module but **not** both
+    ///
+    /// Must only be used when the specific resolution is unimportant such as in
+    /// `missing_enforced_import_renames`
+    Arbitrary,
+}
+
+impl PathNS {
+    fn matches(self, ns: Option<Namespace>) -> bool {
+        let required = match self {
+            PathNS::Type => TypeNS,
+            PathNS::Value => ValueNS,
+            PathNS::Macro => MacroNS,
+            PathNS::Arbitrary => return true,
+        };
+
+        ns == Some(required)
+    }
+}
+
+/// Lazily resolves a path into a list of [`DefId`]s using [`lookup_path`].
+///
+/// Typically it will contain one [`DefId`] or none, but in some situations there can be multiple:
+/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0
+/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls
+///   ([1], [2], [3])
+///
+/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
+/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1
+/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2
+pub struct PathLookup {
+    ns: PathNS,
+    path: &'static [Symbol],
+    once: OnceLock<Vec<DefId>>,
+}
+
+impl PathLookup {
+    /// Only exported for tests and `clippy_lints_internal`
+    #[doc(hidden)]
+    pub const fn new(ns: PathNS, path: &'static [Symbol]) -> Self {
+        Self {
+            ns,
+            path,
+            once: OnceLock::new(),
+        }
+    }
+
+    /// Returns the list of [`DefId`]s that the path resolves to
+    pub fn get(&self, cx: &LateContext<'_>) -> &[DefId] {
+        self.once.get_or_init(|| lookup_path(cx.tcx, self.ns, self.path))
+    }
 
-// Paths in clippy itself
-pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"];
-pub const CLIPPY_SYM_MODULE: [&str; 2] = ["clippy_utils", "sym"];
+    /// Returns the single [`DefId`] that the path resolves to, this can only be used for paths into
+    /// stdlib crates to avoid the issue of multiple [`DefId`]s being returned
+    ///
+    /// May return [`None`] in `no_std`/`no_core` environments
+    pub fn only(&self, cx: &LateContext<'_>) -> Option<DefId> {
+        let ids = self.get(cx);
+        debug_assert!(STDLIB_STABLE_CRATES.contains(&self.path[0]));
+        debug_assert!(ids.len() <= 1, "{ids:?}");
+        ids.first().copied()
+    }
+
+    /// Checks if the path resolves to the given `def_id`
+    pub fn matches(&self, cx: &LateContext<'_>, def_id: DefId) -> bool {
+        self.get(cx).contains(&def_id)
+    }
+
+    /// Resolves `maybe_path` to a [`DefId`] and checks if the [`PathLookup`] matches it
+    pub fn matches_path<'tcx>(&self, cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> bool {
+        path_def_id(cx, maybe_path).is_some_and(|def_id| self.matches(cx, def_id))
+    }
+
+    /// Checks if the path resolves to `ty`'s definition, must be an `Adt`
+    pub fn matches_ty(&self, cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+        ty.ty_adt_def().is_some_and(|adt| self.matches(cx, adt.did()))
+    }
+}
+
+macro_rules! path_macros {
+    ($($name:ident: $ns:expr,)*) => {
+        $(
+            /// Only exported for tests and `clippy_lints_internal`
+            #[doc(hidden)]
+            #[macro_export]
+            macro_rules! $name {
+                ($$($$seg:ident $$(::)?)*) => {
+                    PathLookup::new($ns, &[$$(sym::$$seg,)*])
+                };
+            }
+        )*
+    };
+}
+
+path_macros! {
+    type_path: PathNS::Type,
+    value_path: PathNS::Value,
+    macro_path: PathNS::Macro,
+}
+
+// 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 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);
+pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref);
 
 // Paths in external crates
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
-pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
-pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
-pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
-pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
-pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
-pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
-pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
-pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"];
-pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
-pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
-pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
-pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
-pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"];
+pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
+pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);
+pub static ITERTOOLS_NEXT_TUPLE: PathLookup = value_path!(itertools::Itertools::next_tuple);
+pub static PARKING_LOT_GUARDS: [PathLookup; 3] = [
+    type_path!(lock_api::mutex::MutexGuard),
+    type_path!(lock_api::rwlock::RwLockReadGuard),
+    type_path!(lock_api::rwlock::RwLockWriteGuard),
+];
+pub static REGEX_BUILDER_NEW: PathLookup = value_path!(regex::RegexBuilder::new);
+pub static REGEX_BYTES_BUILDER_NEW: PathLookup = value_path!(regex::bytes::RegexBuilder::new);
+pub static REGEX_BYTES_NEW: PathLookup = value_path!(regex::bytes::Regex::new);
+pub static REGEX_BYTES_SET_NEW: PathLookup = value_path!(regex::bytes::RegexSet::new);
+pub static REGEX_NEW: PathLookup = value_path!(regex::Regex::new);
+pub static REGEX_SET_NEW: PathLookup = value_path!(regex::RegexSet::new);
+pub static SERDE_DESERIALIZE: PathLookup = type_path!(serde::de::Deserialize);
+pub static SERDE_DE_VISITOR: PathLookup = type_path!(serde::de::Visitor);
+pub static TOKIO_FILE_OPTIONS: PathLookup = value_path!(tokio::fs::File::options);
+pub static TOKIO_IO_ASYNCREADEXT: PathLookup = type_path!(tokio::io::AsyncReadExt);
+pub static TOKIO_IO_ASYNCWRITEEXT: PathLookup = type_path!(tokio::io::AsyncWriteExt);
+pub static TOKIO_IO_OPEN_OPTIONS: PathLookup = type_path!(tokio::fs::OpenOptions);
+pub static TOKIO_IO_OPEN_OPTIONS_NEW: PathLookup = value_path!(tokio::fs::OpenOptions::new);
+pub static LAZY_STATIC: PathLookup = macro_path!(lazy_static::lazy_static);
+pub static ONCE_CELL_SYNC_LAZY: PathLookup = type_path!(once_cell::sync::Lazy);
+pub static ONCE_CELL_SYNC_LAZY_NEW: PathLookup = value_path!(once_cell::sync::Lazy::new);
+
+// Paths for internal lints go in `clippy_lints_internal/src/internal_paths.rs`
+
+/// Equivalent to a [`lookup_path`] after splitting the input string on `::`
+///
+/// This function is expensive and should be used sparingly.
+pub fn lookup_path_str(tcx: TyCtxt<'_>, ns: PathNS, path: &str) -> Vec<DefId> {
+    let path: Vec<Symbol> = path.split("::").map(Symbol::intern).collect();
+    lookup_path(tcx, ns, &path)
+}
+
+/// Resolves a def path like `std::vec::Vec`.
+///
+/// Typically it will return one [`DefId`] or none, but in some situations there can be multiple:
+/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0
+/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls
+///   ([1], [2], [3])
+///
+/// This function is expensive and should be used sparingly.
+///
+/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
+/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1
+/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2
+pub fn lookup_path(tcx: TyCtxt<'_>, ns: PathNS, path: &[Symbol]) -> Vec<DefId> {
+    let (root, rest) = match *path {
+        [] | [_] => return Vec::new(),
+        [root, ref rest @ ..] => (root, rest),
+    };
+
+    let mut out = Vec::new();
+    for &base in find_crates(tcx, root).iter().chain(find_primitive_impls(tcx, root)) {
+        lookup_with_base(tcx, base, ns, rest, &mut out);
+    }
+    out
+}
+
+/// Finds the crates called `name`, may be multiple due to multiple major versions.
+pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> &'static [DefId] {
+    static BY_NAME: OnceLock<FxHashMap<Symbol, Vec<DefId>>> = OnceLock::new();
+    let map = BY_NAME.get_or_init(|| {
+        let mut map = FxHashMap::default();
+        map.insert(tcx.crate_name(LOCAL_CRATE), vec![LOCAL_CRATE.as_def_id()]);
+        for &num in tcx.crates(()) {
+            map.entry(tcx.crate_name(num)).or_default().push(num.as_def_id());
+        }
+        map
+    });
+    match map.get(&name) {
+        Some(def_ids) => def_ids,
+        None => &[],
+    }
+}
+
+fn find_primitive_impls(tcx: TyCtxt<'_>, name: Symbol) -> &[DefId] {
+    let ty = match name {
+        sym::bool => SimplifiedType::Bool,
+        sym::char => SimplifiedType::Char,
+        sym::str => SimplifiedType::Str,
+        sym::array => SimplifiedType::Array,
+        sym::slice => SimplifiedType::Slice,
+        // FIXME: rustdoc documents these two using just `pointer`.
+        //
+        // Maybe this is something we should do here too.
+        sym::const_ptr => SimplifiedType::Ptr(Mutability::Not),
+        sym::mut_ptr => SimplifiedType::Ptr(Mutability::Mut),
+        sym::isize => SimplifiedType::Int(IntTy::Isize),
+        sym::i8 => SimplifiedType::Int(IntTy::I8),
+        sym::i16 => SimplifiedType::Int(IntTy::I16),
+        sym::i32 => SimplifiedType::Int(IntTy::I32),
+        sym::i64 => SimplifiedType::Int(IntTy::I64),
+        sym::i128 => SimplifiedType::Int(IntTy::I128),
+        sym::usize => SimplifiedType::Uint(UintTy::Usize),
+        sym::u8 => SimplifiedType::Uint(UintTy::U8),
+        sym::u16 => SimplifiedType::Uint(UintTy::U16),
+        sym::u32 => SimplifiedType::Uint(UintTy::U32),
+        sym::u64 => SimplifiedType::Uint(UintTy::U64),
+        sym::u128 => SimplifiedType::Uint(UintTy::U128),
+        sym::f32 => SimplifiedType::Float(FloatTy::F32),
+        sym::f64 => SimplifiedType::Float(FloatTy::F64),
+        _ => return &[],
+    };
+
+    tcx.incoherent_impls(ty)
+}
+
+/// Resolves a def path like `vec::Vec` with the base `std`.
+fn lookup_with_base(tcx: TyCtxt<'_>, mut base: DefId, ns: PathNS, mut path: &[Symbol], out: &mut Vec<DefId>) {
+    loop {
+        match *path {
+            [segment] => {
+                out.extend(item_child_by_name(tcx, base, ns, segment));
+
+                // When the current def_id is e.g. `struct S`, check the impl items in
+                // `impl S { ... }`
+                let inherent_impl_children = tcx
+                    .inherent_impls(base)
+                    .iter()
+                    .filter_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, ns, segment));
+                out.extend(inherent_impl_children);
+
+                return;
+            },
+            [segment, ref rest @ ..] => {
+                path = rest;
+                let Some(child) = item_child_by_name(tcx, base, PathNS::Type, segment) else {
+                    return;
+                };
+                base = child;
+            },
+            [] => unreachable!(),
+        }
+    }
+}
+
+fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
+    if let Some(local_id) = def_id.as_local() {
+        local_item_child_by_name(tcx, local_id, ns, name)
+    } else {
+        non_local_item_child_by_name(tcx, def_id, ns, name)
+    }
+}
+
+fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, name: Symbol) -> Option<DefId> {
+    let root_mod;
+    let item_kind = match tcx.hir_node_by_def_id(local_id) {
+        Node::Crate(r#mod) => {
+            root_mod = ItemKind::Mod(Ident::dummy(), r#mod);
+            &root_mod
+        },
+        Node::Item(item) => &item.kind,
+        _ => return None,
+    };
+
+    let res = |ident: Ident, owner_id: OwnerId| {
+        if ident.name == name && ns.matches(tcx.def_kind(owner_id).ns()) {
+            Some(owner_id.to_def_id())
+        } else {
+            None
+        }
+    };
+
+    match item_kind {
+        ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| {
+            let item = tcx.hir_item(item_id);
+            if let ItemKind::Use(path, UseKind::Single(ident)) = item.kind {
+                if ident.name == name {
+                    path.res
+                        .iter()
+                        .find(|res| ns.matches(res.ns()))
+                        .and_then(Res::opt_def_id)
+                } else {
+                    None
+                }
+            } else {
+                res(item.kind.ident()?, item_id.owner_id)
+            }
+        }),
+        ItemKind::Impl(r#impl) => r#impl
+            .items
+            .iter()
+            .find_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id)),
+        ItemKind::Trait(.., trait_item_refs) => trait_item_refs
+            .iter()
+            .find_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id)),
+        _ => None,
+    }
+}
+
+fn non_local_item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
+    match tcx.def_kind(def_id) {
+        DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx.module_children(def_id).iter().find_map(|child| {
+            if child.ident.name == name && ns.matches(child.res.ns()) {
+                child.res.opt_def_id()
+            } else {
+                None
+            }
+        }),
+        DefKind::Impl { .. } => tcx
+            .associated_item_def_ids(def_id)
+            .iter()
+            .copied()
+            .find(|assoc_def_id| tcx.item_name(*assoc_def_id) == name && ns.matches(tcx.def_kind(assoc_def_id).ns())),
+        _ => None,
+    }
+}
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/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 1a30b473d10..9428262b99a 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -1,6 +1,6 @@
 #![allow(non_upper_case_globals)]
 
-use rustc_span::symbol::{PREDEFINED_SYMBOLS_COUNT, Symbol};
+use rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT;
 
 #[doc(no_inline)]
 pub use rustc_span::sym::*;
@@ -24,46 +24,177 @@ macro_rules! generate {
         ];
 
         $(
-            pub const $name: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()});
+            pub const $name: rustc_span::Symbol = rustc_span::Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()});
         )*
     };
 }
 
 generate! {
+    abs,
+    align_of,
+    ambiguous_glob_reexports,
     as_bytes,
     as_deref_mut,
     as_deref,
     as_mut,
+    AsyncReadExt,
+    AsyncWriteExt,
+    BACKSLASH_SINGLE_QUOTE: r"\'",
     Binary,
+    build_hasher,
+    bytes,
+    cargo_clippy: "cargo-clippy",
     Cargo_toml: "Cargo.toml",
+    cast,
+    chars,
     CLIPPY_ARGS,
     CLIPPY_CONF_DIR,
+    clippy_utils,
+    clone_into,
     cloned,
+    collect,
+    const_ptr,
     contains,
     copied,
+    CRLF: "\r\n",
     Current,
+    de,
+    Deserialize,
+    diagnostics,
+    disallowed_types,
+    DOUBLE_QUOTE: "\"",
+    EarlyLintPass,
+    ends_with,
+    enum_glob_use,
+    error,
+    ErrorKind,
+    exp,
+    extend,
+    finish_non_exhaustive,
+    finish,
+    flat_map,
+    for_each,
+    from_bytes_with_nul_unchecked,
+    from_bytes_with_nul,
+    from_ptr,
+    from_raw,
+    from_ref,
+    from_str_radix,
+    fs,
+    futures_util,
     get,
+    hidden_glob_reexports,
+    hygiene,
     insert,
     int_roundings,
+    into_bytes,
+    into_owned,
     IntoIter,
+    io,
+    is_ascii,
     is_empty,
+    is_err,
+    is_none,
     is_ok,
     is_some,
+    itertools,
+    Itertools,
+    kw,
+    last,
+    lazy_static,
+    Lazy,
+    LF: "\n",
+    Lint,
+    ln,
+    lock_api,
+    log,
     LowerExp,
     LowerHex,
+    macro_use_imports,
+    map_or_else,
+    map_or,
+    max,
+    MAX,
+    mem,
+    min,
+    MIN,
+    mode,
+    module_name_repetitions,
     msrv,
+    msrvs,
+    MsrvStack,
+    mut_ptr,
+    mutex,
+    needless_return,
+    next_tuple,
     Octal,
+    once_cell,
+    OpenOptions,
     or_default,
+    Other,
+    parse,
+    PathLookup,
+    paths,
+    powf,
+    powi,
+    push,
+    redundant_pub_crate,
     regex,
+    Regex,
+    RegexBuilder,
+    RegexSet,
+    reserve,
+    resize,
+    restriction,
+    rustc_lint_defs,
+    rustc_lint,
+    rustc_span,
     rustfmt_skip,
+    rwlock,
+    serde,
+    set_len,
+    set_mode,
+    set_readonly,
+    signum,
+    single_component_path_imports,
+    span_lint_and_then,
+    split_whitespace,
+    split,
+    sqrt,
     Start,
+    Step,
+    style,
+    symbol,
+    Symbol,
+    SyntaxContext,
+    take,
+    TBD,
+    then_some,
+    to_ascii_lowercase,
+    to_ascii_uppercase,
+    to_digit,
+    to_lowercase,
     to_owned,
+    to_uppercase,
+    tokio,
+    unreachable_pub,
+    unsafe_removed_from_name,
+    unused_braces,
     unused_extern_crates,
+    unused_import_braces,
+    unused_trait_names,
+    unused,
     unwrap_err,
     unwrap_or_default,
+    unwrap_or_else,
     UpperExp,
     UpperHex,
     V4,
     V6,
+    Visitor,
+    warnings,
     Weak,
+    wildcard_imports,
+    with_capacity,
+    wrapping_offset,
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 8db9cd593b3..26d41cfb497 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -20,8 +20,8 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -32,7 +32,8 @@ use std::assert_matches::debug_assert_matches;
 use std::collections::hash_map::Entry;
 use std::iter;
 
-use crate::{def_path_def_ids, match_def_path, path_res};
+use crate::path_res;
+use crate::paths::{PathNS, lookup_path_str};
 
 mod type_certainty;
 pub use type_certainty::expr_type_is_certain;
@@ -229,9 +230,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
 /// Checks whether a type implements a trait.
 /// The function returns false in case the type contains an inference variable.
 ///
-/// See:
-/// * [`get_trait_def_id`](super::get_trait_def_id) to get a trait [`DefId`].
-/// * [Common tools for writing lints] for an example how to use this function and other options.
+/// See [Common tools for writing lints] for an example how to use this function and other options.
 ///
 /// [Common tools for writing lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md#checking-if-a-type-implements-a-specific-trait
 pub fn implements_trait<'tcx>(
@@ -359,56 +358,6 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     }
 }
 
-// FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
-// this function can be removed once the `normalize` method does not panic when normalization does
-// not succeed
-/// Checks if `Ty` is normalizable. This function is useful
-/// to avoid crashes on `layout_of`.
-pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-    is_normalizable_helper(cx, param_env, ty, 0, &mut FxHashMap::default())
-}
-
-fn is_normalizable_helper<'tcx>(
-    cx: &LateContext<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    depth: usize,
-    cache: &mut FxHashMap<Ty<'tcx>, bool>,
-) -> bool {
-    if let Some(&cached_result) = cache.get(&ty) {
-        return cached_result;
-    }
-    if !cx.tcx.recursion_limit().value_within_limit(depth) {
-        return false;
-    }
-    // Prevent recursive loops by answering `true` to recursive requests with the same
-    // type. This will be adjusted when the outermost call analyzes all the type
-    // components.
-    cache.insert(ty, true);
-    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
-    let cause = ObligationCause::dummy();
-    let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
-        match ty.kind() {
-            ty::Adt(def, args) => def.variants().iter().all(|variant| {
-                variant
-                    .fields
-                    .iter()
-                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), depth + 1, cache))
-            }),
-            _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
-                GenericArgKind::Type(inner_ty) if inner_ty != ty => {
-                    is_normalizable_helper(cx, param_env, inner_ty, depth + 1, cache)
-                },
-                _ => true, // if inner_ty == ty, we've already checked it
-            }),
-        }
-    } else {
-        false
-    };
-    cache.insert(ty, result);
-    result
-}
-
 /// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
 /// integer or floating-point number type).
 ///
@@ -474,17 +423,6 @@ pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 }
 
-/// Checks if type is struct, enum or union type with the given def path.
-///
-/// If the type is a diagnostic item, use `is_type_diagnostic_item` instead.
-/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
-pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
-    match ty.kind() {
-        ty::Adt(adt, _) => match_def_path(cx, adt.did(), path),
-        _ => false,
-    }
-}
-
 /// Checks if the drop order for a type matters.
 ///
 /// Some std types implement drop solely to deallocate memory. For these types, and composites
@@ -915,7 +853,7 @@ pub fn for_each_top_level_late_bound_region<B>(
                 ControlFlow::Continue(())
             }
         }
-        fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
+        fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
             self.index += 1;
             let res = t.super_visit_with(self);
             self.index -= 1;
@@ -993,9 +931,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
 /// account the layout of type parameters.
 pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
     use rustc_middle::ty::layout::LayoutOf;
-    if !is_normalizable(cx, cx.param_env, ty) {
-        return 0;
-    }
     match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) {
         (Ok(size), _) => size,
         (Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(),
@@ -1184,10 +1119,7 @@ impl<'tcx> InteriorMut<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, ignore_interior_mutability: &[String]) -> Self {
         let ignored_def_ids = ignore_interior_mutability
             .iter()
-            .flat_map(|ignored_ty| {
-                let path: Vec<&str> = ignored_ty.split("::").collect();
-                def_path_def_ids(tcx, path.as_slice())
-            })
+            .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty))
             .collect();
 
         Self {
@@ -1422,3 +1354,10 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'
     let mut phantoms = FxHashSet::default();
     has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty)
 }
+
+/// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec<T>`.
+pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_slice()
+        || ty.is_array()
+        || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 3398ff8af2f..6e358662327 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -11,14 +11,14 @@
 //! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
 //! be considered a bug.
 
-use crate::def_path_res;
+use crate::paths::{PathNS, lookup_path};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
 use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 
 mod certainty;
 use certainty::{Certainty, Meet, join, meet};
@@ -194,7 +194,7 @@ fn path_segment_certainty(
     path_segment: &PathSegment<'_>,
     resolves_to_type: bool,
 ) -> Certainty {
-    let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) {
+    let certainty = match update_res(cx, parent_certainty, path_segment, resolves_to_type).unwrap_or(path_segment.res) {
         // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or
         // an unparameterized type), or the generics are instantiated with arguments that are certain.
         //
@@ -267,17 +267,24 @@ fn path_segment_certainty(
 
 /// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`.
 /// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`.
-fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> {
+fn update_res(
+    cx: &LateContext<'_>,
+    parent_certainty: Certainty,
+    path_segment: &PathSegment<'_>,
+    resolves_to_type: bool,
+) -> Option<Res> {
     if path_segment.res == Res::Err
         && let Some(def_id) = parent_certainty.to_def_id()
     {
         let mut def_path = cx.get_def_path(def_id);
         def_path.push(path_segment.ident.name);
-        let reses = def_path_res(cx.tcx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>());
-        if let [res] = reses.as_slice() { Some(*res) } else { None }
-    } else {
-        None
+        let ns = if resolves_to_type { PathNS::Type } else { PathNS::Value };
+        if let &[id] = lookup_path(cx.tcx, ns, &def_path).as_slice() {
+            return Some(Res::Def(cx.tcx.def_kind(id), id));
+        }
     }
+
+    None
 }
 
 #[allow(clippy::cast_possible_truncation)]
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index fe488ef89da..d4bf6cd48a1 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -6,7 +6,6 @@
 // positives.
 
 #![feature(iter_collect_into)]
-#![feature(let_chains)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index d2f79da1a54..da41bdd27bc 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-04-22"
+channel = "nightly-2025-05-14"
 # 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 87ca9c5bedd..f8acf88cf81 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -1,7 +1,6 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 #![feature(rustc_private)]
-#![feature(let_chains)]
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 6d391bd622a..78b27e2f613 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, let_chains)]
+#![feature(rustc_private)]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 16a1a415102..4ac2bd53285 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -44,8 +44,8 @@ fn dogfood() {
         "rustc_tools_util",
     ] {
         println!("linting {package}");
-        if !run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]) {
-            failed_packages.push(if package.is_empty() { "root" } else { package });
+        if !run_clippy_for_package(package) {
+            failed_packages.push(package);
         }
     }
 
@@ -57,7 +57,7 @@ fn dogfood() {
 }
 
 #[must_use]
-fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
+fn run_clippy_for_package(project: &str) -> bool {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
     let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH);
@@ -79,15 +79,17 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
         }
     }
 
-    command.arg("--").args(args);
+    command.arg("--");
     command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
-    command.args(["-D", "clippy::dbg_macro"]);
-
+    command.args(["-D", "clippy::all", "-D", "clippy::pedantic", "-D", "clippy::dbg_macro"]);
     if !cfg!(feature = "internal") {
         // running a clippy built without internal lints on the clippy source
-        // that contains e.g. `allow(clippy::invalid_paths)`
+        // that contains e.g. `allow(clippy::symbol_as_str)`
         command.args(["-A", "unknown_lints"]);
     }
 
+    // Workaround for not being a workspace, add the crate's directory back to the path
+    command.args(["--remap-path-prefix", &format!("={project}")]);
+
     command.status().unwrap().success()
 }
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 13cf36823c5..cb7d61eee24 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -30,7 +30,7 @@ fn integration_test() {
 
     let repo_dir = tempfile::tempdir()
         .expect("couldn't create temp dir")
-        .into_path()
+        .keep()
         .join(crate_name);
 
     let st = Command::new("git")
diff --git a/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs b/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
deleted file mode 100644
index f730f564a09..00000000000
--- a/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![allow(clippy::unnecessary_def_path)]
-
-pub static OPTION: [&str; 3] = ["core", "option", "Option"];
-pub const RESULT: &[&str] = &["core", "result", "Result"];
diff --git a/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.rs
new file mode 100644
index 00000000000..9dc8e9e8f4c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.rs
@@ -0,0 +1,60 @@
+#![deny(clippy::derive_deserialize_allowing_unknown)]
+
+use serde::{Deserialize, Deserializer};
+
+#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown
+struct Struct {
+    flag: bool,
+    limit: u64,
+}
+
+#[derive(Deserialize)] //~ derive_deserialize_allowing_unknown
+enum Enum {
+    A(bool),
+    B { limit: u64 },
+}
+
+// negative tests
+
+#[derive(Deserialize)]
+#[serde(deny_unknown_fields)]
+struct StructWithDenyUnknownFields {
+    flag: bool,
+    limit: u64,
+}
+
+#[derive(Deserialize)]
+#[serde(deny_unknown_fields)]
+enum EnumWithDenyUnknownFields {
+    A(bool),
+    B { limit: u64 },
+}
+
+#[derive(Deserialize)]
+#[serde(untagged, deny_unknown_fields)]
+enum MultipleSerdeAttributes {
+    A(bool),
+    B { limit: u64 },
+}
+
+#[derive(Deserialize)]
+struct TupleStruct(u64, bool);
+
+#[derive(Deserialize)]
+#[serde(deny_unknown_fields)]
+enum EnumWithOnlyTupleVariants {
+    A(bool),
+    B(u64),
+}
+
+struct ManualSerdeImplementation;
+
+impl<'de> Deserialize<'de> for ManualSerdeImplementation {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let () = <() as Deserialize>::deserialize(deserializer)?;
+        Ok(ManualSerdeImplementation)
+    }
+}
diff --git a/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.stderr b/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.stderr
new file mode 100644
index 00000000000..93d64826c99
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/derive_deserialize_allowing_unknown.stderr
@@ -0,0 +1,23 @@
+error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`
+  --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:5:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:1:9
+   |
+LL | #![deny(clippy::derive_deserialize_allowing_unknown)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `#[derive(serde::Deserialize)]` without `#[serde(deny_unknown_fields)]`
+  --> tests/ui-internal/derive_deserialize_allowing_unknown.rs:11:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals.stderr b/src/tools/clippy/tests/ui-internal/interning_literals.stderr
index 628b97eff84..9ff4194e542 100644
--- a/src/tools/clippy/tests/ui-internal/interning_literals.stderr
+++ b/src/tools/clippy/tests/ui-internal/interning_literals.stderr
@@ -4,9 +4,10 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("f32");
    |             ^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::interning-literals` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
-help: use the preinterned symbol
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("f32");
 LL +     let _ = sym::f32;
@@ -18,7 +19,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("proc-macro");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("proc-macro");
 LL +     let _ = sym::proc_dash_macro;
@@ -30,7 +32,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("self");
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("self");
 LL +     let _ = kw::SelfLower;
@@ -42,7 +45,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("msrv");
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("msrv");
 LL +     let _ = sym::msrv;
@@ -54,7 +58,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("Cargo.toml");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use the preinterned symbol
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("Cargo.toml");
 LL +     let _ = sym::Cargo_toml;
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr
index 8294453a8f9..879d9e633c2 100644
--- a/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr
+++ b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr
@@ -4,9 +4,10 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("xyz123");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
    = note: `-D clippy::interning-literals` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("xyz123");
 LL +     let _ = sym::xyz123;
@@ -18,7 +19,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("with-dash");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("with-dash");
 LL +     let _ = sym::with_dash;
@@ -30,7 +32,8 @@ error: interning a string literal
 LL |     let _ = Symbol::intern("with.dot");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: add the symbol to `clippy_utils/src/sym.rs` and use it
+   = help: add the symbol to `clippy_utils/src/sym.rs` if needed
+help: use a preinterned symbol instead
    |
 LL -     let _ = Symbol::intern("with.dot");
 LL +     let _ = sym::with_dot;
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.rs b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
deleted file mode 100644
index 7317abc2185..00000000000
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-#![deny(clippy::invalid_paths)]
-#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)]
-
-mod paths {
-    // Good path
-    pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
-
-    // Path to method on inherent impl of a primitive type
-    pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
-
-    // Path to method on inherent impl
-    pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
-
-    // Path with empty segment
-    pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
-    //~^ invalid_paths
-
-    // Path with bad crate
-    pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
-    //~^ invalid_paths
-
-    // Path with bad module
-    pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"];
-    //~^ invalid_paths
-
-    // Path to method on an enum inherent impl
-    pub const OPTION_IS_SOME: [&str; 4] = ["core", "option", "Option", "is_some"];
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
deleted file mode 100644
index 7b7b25ce8d8..00000000000
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error: invalid path
-  --> tests/ui-internal/invalid_paths.rs:15:5
-   |
-LL |     pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: the lint level is defined here
-  --> tests/ui-internal/invalid_paths.rs:1:9
-   |
-LL | #![deny(clippy::invalid_paths)]
-   |         ^^^^^^^^^^^^^^^^^^^^^
-
-error: invalid path
-  --> tests/ui-internal/invalid_paths.rs:19:5
-   |
-LL |     pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: invalid path
-  --> tests/ui-internal/invalid_paths.rs:23:5
-   |
-LL |     pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed
new file mode 100644
index 00000000000..6a71b16c604
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed
@@ -0,0 +1,28 @@
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn f(s: Symbol) {
+    s == sym::f32;
+    //~^ symbol_as_str
+    s == sym::proc_dash_macro;
+    //~^ symbol_as_str
+    s == kw::SelfLower;
+    //~^ symbol_as_str
+    s == sym::msrv;
+    //~^ symbol_as_str
+    s == sym::Cargo_toml;
+    //~^ symbol_as_str
+    sym::get == s;
+    //~^ symbol_as_str
+
+    let _ = match s {
+        //~^ symbol_as_str
+        sym::unwrap_err => 1,
+        sym::unwrap_or_default | sym::unwrap_or_else => 2,
+        _ => 3,
+    };
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs
new file mode 100644
index 00000000000..43136504bf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs
@@ -0,0 +1,28 @@
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn f(s: Symbol) {
+    s.as_str() == "f32";
+    //~^ symbol_as_str
+    s.as_str() == "proc-macro";
+    //~^ symbol_as_str
+    s.as_str() == "self";
+    //~^ symbol_as_str
+    s.as_str() == "msrv";
+    //~^ symbol_as_str
+    s.as_str() == "Cargo.toml";
+    //~^ symbol_as_str
+    "get" == s.as_str();
+    //~^ symbol_as_str
+
+    let _ = match s.as_str() {
+        //~^ symbol_as_str
+        "unwrap_err" => 1,
+        "unwrap_or_default" | "unwrap_or_else" => 2,
+        _ => 3,
+    };
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr
new file mode 100644
index 00000000000..3eeead4aa8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr
@@ -0,0 +1,97 @@
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:9:5
+   |
+LL |     s.as_str() == "f32";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+   = note: `-D clippy::symbol-as-str` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "f32";
+LL +     s == sym::f32;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:11:5
+   |
+LL |     s.as_str() == "proc-macro";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "proc-macro";
+LL +     s == sym::proc_dash_macro;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:13:5
+   |
+LL |     s.as_str() == "self";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "self";
+LL +     s == kw::SelfLower;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:15:5
+   |
+LL |     s.as_str() == "msrv";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "msrv";
+LL +     s == sym::msrv;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:17:5
+   |
+LL |     s.as_str() == "Cargo.toml";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "Cargo.toml";
+LL +     s == sym::Cargo_toml;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:19:14
+   |
+LL |     "get" == s.as_str();
+   |              ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     "get" == s.as_str();
+LL +     sym::get == s;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str.rs:22:19
+   |
+LL |     let _ = match s.as_str() {
+   |                   ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL ~     let _ = match s {
+LL |
+LL ~         sym::unwrap_err => 1,
+LL ~         sym::unwrap_or_default | sym::unwrap_or_else => 2,
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs
new file mode 100644
index 00000000000..635f28007e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs
@@ -0,0 +1,15 @@
+//@no-rustfix: paths that don't exist yet
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use rustc_span::Symbol;
+
+fn f(s: Symbol) {
+    s.as_str() == "xyz123";
+    //~^ symbol_as_str
+    s.as_str() == "with-dash";
+    //~^ symbol_as_str
+    s.as_str() == "with.dot";
+    //~^ symbol_as_str
+}
diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr
new file mode 100644
index 00000000000..65664ebb451
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr
@@ -0,0 +1,43 @@
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:9:5
+   |
+LL |     s.as_str() == "xyz123";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+   = note: `-D clippy::symbol-as-str` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]`
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "xyz123";
+LL +     s == sym::xyz123;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:11:5
+   |
+LL |     s.as_str() == "with-dash";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "with-dash";
+LL +     s == sym::with_dash;
+   |
+
+error: converting a Symbol to a string
+  --> tests/ui-internal/symbol_as_str_unfixable.rs:13:5
+   |
+LL |     s.as_str() == "with.dot";
+   |     ^^^^^^^^^^
+   |
+   = help: add the symbols to `clippy_utils/src/sym.rs` if needed
+help: use preinterned symbols instead
+   |
+LL -     s.as_str() == "with.dot";
+LL +     s == sym::with_dot;
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
deleted file mode 100644
index 89902ebe4e5..00000000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
+++ /dev/null
@@ -1,77 +0,0 @@
-//@aux-build:paths.rs
-#![deny(clippy::unnecessary_def_path)]
-#![feature(rustc_private)]
-#![allow(clippy::unnecessary_map_or)]
-
-extern crate clippy_utils;
-extern crate paths;
-extern crate rustc_hir;
-extern crate rustc_lint;
-extern crate rustc_middle;
-extern crate rustc_span;
-
-#[allow(unused)]
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
-#[allow(unused)]
-use clippy_utils::{
-    is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method,
-    match_def_path, match_trait_method, path_res,
-};
-
-#[allow(unused)]
-use rustc_hir::LangItem;
-#[allow(unused)]
-use rustc_span::sym;
-
-use rustc_hir::Expr;
-use rustc_hir::def_id::DefId;
-use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
-
-#[allow(unused, clippy::unnecessary_def_path)]
-static OPTION: [&str; 3] = ["core", "option", "Option"];
-#[allow(unused, clippy::unnecessary_def_path)]
-const RESULT: &[&str] = &["core", "result", "Result"];
-
-fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
-    let _ = is_type_diagnostic_item(cx, ty, sym::Option);
-    //~^ unnecessary_def_path
-    let _ = is_type_diagnostic_item(cx, ty, sym::Result);
-    //~^ unnecessary_def_path
-    let _ = is_type_diagnostic_item(cx, ty, sym::Result);
-    //~^ unnecessary_def_path
-
-    #[allow(unused, clippy::unnecessary_def_path)]
-    let rc_path = &["alloc", "rc", "Rc"];
-    let _ = is_type_diagnostic_item(cx, ty, sym::Rc);
-    //~^ unnecessary_def_path
-
-    let _ = is_type_diagnostic_item(cx, ty, sym::Option);
-    //~^ unnecessary_def_path
-    let _ = is_type_diagnostic_item(cx, ty, sym::Result);
-    //~^ unnecessary_def_path
-
-    let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox);
-    //~^ unnecessary_def_path
-    let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit);
-    //~^ unnecessary_def_path
-
-    let _ = cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did);
-    //~^ unnecessary_def_path
-    let _ = cx.tcx.is_diagnostic_item(sym::Option, did);
-    //~^ unnecessary_def_path
-    let _ = cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did);
-    //~^ unnecessary_def_path
-
-    let _ = is_trait_method(cx, expr, sym::AsRef);
-    //~^ unnecessary_def_path
-
-    let _ = is_path_diagnostic_item(cx, expr, sym::Option);
-    //~^ unnecessary_def_path
-    let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id));
-    //~^ unnecessary_def_path
-    let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome);
-    //~^ unnecessary_def_path
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
index cfca15267c1..5cd3254188d 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
@@ -1,77 +1,20 @@
-//@aux-build:paths.rs
-#![deny(clippy::unnecessary_def_path)]
 #![feature(rustc_private)]
-#![allow(clippy::unnecessary_map_or)]
 
-extern crate clippy_utils;
-extern crate paths;
-extern crate rustc_hir;
-extern crate rustc_lint;
-extern crate rustc_middle;
-extern crate rustc_span;
+use clippy_utils::paths::{PathLookup, PathNS};
+use clippy_utils::{macro_path, sym, type_path, value_path};
 
-#[allow(unused)]
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
-#[allow(unused)]
-use clippy_utils::{
-    is_enum_variant_ctor, is_expr_path_def_path, is_path_diagnostic_item, is_res_lang_ctor, is_trait_method,
-    match_def_path, match_trait_method, path_res,
-};
+static OPTION: PathLookup = type_path!(core::option::Option);
+//~^ unnecessary_def_path
+static SOME: PathLookup = type_path!(core::option::Option::Some);
+//~^ unnecessary_def_path
 
-#[allow(unused)]
-use rustc_hir::LangItem;
-#[allow(unused)]
-use rustc_span::sym;
+static RESULT: PathLookup = type_path!(core::result::Result);
+//~^ unnecessary_def_path
+static RESULT_VIA_STD: PathLookup = type_path!(std::result::Result);
+//~^ unnecessary_def_path
 
-use rustc_hir::Expr;
-use rustc_hir::def_id::DefId;
-use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+static VEC_NEW: PathLookup = value_path!(alloc::vec::Vec::new);
+//~^ unnecessary_def_path
 
-#[allow(unused, clippy::unnecessary_def_path)]
-static OPTION: [&str; 3] = ["core", "option", "Option"];
-#[allow(unused, clippy::unnecessary_def_path)]
-const RESULT: &[&str] = &["core", "result", "Result"];
-
-fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
-    let _ = match_type(cx, ty, &OPTION);
-    //~^ unnecessary_def_path
-    let _ = match_type(cx, ty, RESULT);
-    //~^ unnecessary_def_path
-    let _ = match_type(cx, ty, &["core", "result", "Result"]);
-    //~^ unnecessary_def_path
-
-    #[allow(unused, clippy::unnecessary_def_path)]
-    let rc_path = &["alloc", "rc", "Rc"];
-    let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
-    //~^ unnecessary_def_path
-
-    let _ = match_type(cx, ty, &paths::OPTION);
-    //~^ unnecessary_def_path
-    let _ = match_type(cx, ty, paths::RESULT);
-    //~^ unnecessary_def_path
-
-    let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
-    //~^ unnecessary_def_path
-    let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
-    //~^ unnecessary_def_path
-
-    let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
-    //~^ unnecessary_def_path
-    let _ = match_def_path(cx, did, &["core", "option", "Option"]);
-    //~^ unnecessary_def_path
-    let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
-    //~^ unnecessary_def_path
-
-    let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
-    //~^ unnecessary_def_path
-
-    let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
-    //~^ unnecessary_def_path
-    let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
-    //~^ unnecessary_def_path
-    let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
-    //~^ unnecessary_def_path
-}
-
-fn main() {}
+static VEC_MACRO: PathLookup = macro_path!(std::vec);
+//~^ unnecessary_def_path
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
index d7fb4ea551e..4abb1be7406 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
@@ -1,100 +1,58 @@
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:37:13
+error: a diagnostic name exists for this path: sym::Option
+  --> tests/ui-internal/unnecessary_def_path.rs:6:29
    |
-LL |     let _ = match_type(cx, ty, &OPTION);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
+LL | static OPTION: PathLookup = type_path!(core::option::Option);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the lint level is defined here
-  --> tests/ui-internal/unnecessary_def_path.rs:2:9
-   |
-LL | #![deny(clippy::unnecessary_def_path)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:39:13
-   |
-LL |     let _ = match_type(cx, ty, RESULT);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils
+   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]`
 
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:41:13
+error: a language item exists for this path: LangItem::OptionSome
+  --> tests/ui-internal/unnecessary_def_path.rs:8:27
    |
-LL |     let _ = match_type(cx, ty, &["core", "result", "Result"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:46:13
+LL | static SOME: PathLookup = type_path!(core::option::Option::Some);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.lang_items` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=lang&filter-crate=clippy_utils
 
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:49:13
+error: a diagnostic name exists for this path: sym::Result
+  --> tests/ui-internal/unnecessary_def_path.rs:11:29
    |
-LL |     let _ = match_type(cx, ty, &paths::OPTION);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:51:13
+LL | static RESULT: PathLookup = type_path!(core::result::Result);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _ = match_type(cx, ty, paths::RESULT);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils
 
-error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:54:13
+error: a diagnostic name exists for this path: sym::Result
+  --> tests/ui-internal/unnecessary_def_path.rs:13:37
    |
-LL |     let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:56:13
+LL | static RESULT_VIA_STD: PathLookup = type_path!(std::result::Result);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils
 
-error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:59:13
+error: a diagnostic name exists for this path: sym::vec_new
+  --> tests/ui-internal/unnecessary_def_path.rs:16:30
    |
-LL |     let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)`
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:61:13
+LL | static VEC_NEW: PathLookup = value_path!(alloc::vec::Vec::new);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _ = match_def_path(cx, did, &["core", "option", "Option"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils
 
-error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:63:13
-   |
-LL |     let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)`
+error: a diagnostic name exists for this path: sym::vec_macro
+  --> tests/ui-internal/unnecessary_def_path.rs:19:32
    |
-   = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:66:13
-   |
-LL |     let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
-
-error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:69:13
-   |
-LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
-
-error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:71:13
-   |
-LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))`
-
-error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:73:13
+LL | static VEC_MACRO: PathLookup = macro_path!(std::vec);
+   |                                ^^^^^^^^^^^^^^^^^^^^^
    |
-LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`
+   = help: remove the `PathLookup` and use utilities such as `cx.tcx.is_diagnostic_item` instead
+   = help: see also https://doc.rust-lang.org/nightly/nightly-rustc/?search=diag&filter-crate=clippy_utils
 
-error: aborting due to 15 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
deleted file mode 100644
index bd7a55114ac..00000000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(rustc_private)]
-#![allow(unused)]
-#![deny(clippy::unnecessary_def_path)]
-
-extern crate rustc_hir;
-
-use rustc_hir::LangItem;
-
-fn main() {
-    const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
-    //~^ unnecessary_def_path
-    const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
-    //~^ unnecessary_def_path
-    const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-    //~^ unnecessary_def_path
-
-    // Don't lint, not a diagnostic or language item
-    const OPS_MOD: [&str; 2] = ["core", "ops"];
-}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
deleted file mode 100644
index 88fdf6f1c18..00000000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: hardcoded path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:10:36
-   |
-LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::Deref`
-note: the lint level is defined here
-  --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:3:9
-   |
-LL | #![deny(clippy::unnecessary_def_path)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: hardcoded path to a language item
-  --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:40
-   |
-LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `LangItem::DerefMut`
-
-error: hardcoded path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:14:43
-   |
-LL |     const OPS_MOD: [&str; 5] = ["core", "ops"];
-   |                                ^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::deref_method`
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed
index f12273954c6..5e189471b00 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::collapsible_if)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs
index 5a984d7a3cb..525eebf632a 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::collapsible_if)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr
index c22a65a4473..c9de166a969 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr
@@ -1,5 +1,5 @@
 error: this `if` statement can be collapsed
-  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:5:5
+  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:4:5
    |
 LL | /     if let Some(a) = Some(3) {
 LL | |         // with comment
@@ -21,7 +21,7 @@ LL ~         }
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:13:5
+  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:12:5
    |
 LL | /     if let Some(a) = Some(3) {
 LL | |         // with comment
@@ -41,7 +41,7 @@ LL ~         }
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:21:5
+  --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:20:5
    |
 LL | /     if Some(3) == Some(4).map(|x| x - 1) {
 LL | |         // with comment
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml
new file mode 100644
index 00000000000..3ed7cedbd14
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/clippy.toml
@@ -0,0 +1 @@
+allow-exact-repetitions = false
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs
new file mode 100644
index 00000000000..20603766624
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::module_name_repetitions)]
+#![allow(dead_code)]
+
+pub mod foo {
+    // this line should produce a warning:
+    pub fn foo() {}
+    //~^ module_name_repetitions
+
+    // but this line shouldn't
+    pub fn to_foo() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr
new file mode 100644
index 00000000000..8e6f726d02c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.stderr
@@ -0,0 +1,11 @@
+error: item name is the same as its containing module's name
+  --> tests/ui-toml/item_name_repetitions/allow_exact_repetitions/item_name_repetitions.rs:6:12
+   |
+LL |     pub fn foo() {}
+   |            ^^^
+   |
+   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::module_name_repetitions)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml
new file mode 100644
index 00000000000..2fe64b2755b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/clippy.toml
@@ -0,0 +1 @@
+missing-docs-allow-unused = true
diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs
new file mode 100644
index 00000000000..155f680c7b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs
@@ -0,0 +1,26 @@
+//! Test file for missing_docs_in_private_items lint with allow_unused configuration
+#![warn(clippy::missing_docs_in_private_items)]
+#![allow(dead_code)]
+
+/// A struct with some documented and undocumented fields
+struct Test {
+    /// This field is documented
+    field1: i32,
+    _unused: i32, // This should not trigger a warning because it starts with an underscore
+    field3: i32,  //~ missing_docs_in_private_items
+}
+
+struct Test2 {
+    //~^ missing_docs_in_private_items
+    _field1: i32, // This should not trigger a warning
+    _field2: i32, // This should not trigger a warning
+}
+
+struct Test3 {
+    //~^ missing_docs_in_private_items
+    /// This field is documented although this is not mandatory
+    _unused: i32, // This should not trigger a warning because it starts with an underscore
+    field2: i32, //~ missing_docs_in_private_items
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr
new file mode 100644
index 00000000000..8f511883e90
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.stderr
@@ -0,0 +1,38 @@
+error: missing documentation for a struct field
+  --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:10:5
+   |
+LL |     field3: i32,
+   |     ^^^^^^^^^^^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
+
+error: missing documentation for a struct
+  --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:13:1
+   |
+LL | / struct Test2 {
+LL | |
+LL | |     _field1: i32, // This should not trigger a warning
+LL | |     _field2: i32, // This should not trigger a warning
+LL | | }
+   | |_^
+
+error: missing documentation for a struct
+  --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:19:1
+   |
+LL | / struct Test3 {
+LL | |
+LL | |     /// This field is documented although this is not mandatory
+LL | |     _unused: i32, // This should not trigger a warning because it starts with an underscore
+LL | |     field2: i32,
+LL | | }
+   | |_^
+
+error: missing documentation for a struct field
+  --> tests/ui-toml/missing_docs_allow_unused/missing_docs_allow_unused.rs:23:5
+   |
+LL |     field2: i32,
+   |     ^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
index 41dbd506847..c7a326f2829 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
@@ -14,4 +14,7 @@ disallowed-methods = [
     "conf_disallowed_methods::Struct::method",
     "conf_disallowed_methods::Trait::provided_method",
     "conf_disallowed_methods::Trait::implemented_method",
+    # re-exports
+    "conf_disallowed_methods::identity",
+    "conf_disallowed_methods::renamed",
 ]
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index dd170d6baf8..2dac01649a0 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -8,6 +8,9 @@ extern crate regex;
 use futures::stream::{empty, select_all};
 use regex::Regex;
 
+use std::convert::identity;
+use std::hint::black_box as renamed;
+
 fn local_fn() {}
 
 struct Struct;
@@ -71,4 +74,9 @@ fn main() {
     //~^ disallowed_methods
     s.implemented_method();
     //~^ disallowed_methods
+
+    identity(());
+    //~^ disallowed_methods
+    renamed(1);
+    //~^ disallowed_methods
 }
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index f7dda81eb93..20474ad6e92 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,5 +1,5 @@
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:33:14
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
    |              ^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let re = Regex::new(r"ab.*c").unwrap();
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:8
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:38:8
    |
 LL |     re.is_match("abc");
    |        ^^^^^^^^
@@ -16,76 +16,88 @@ LL |     re.is_match("abc");
    = note: no matching allowed
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:14
    |
 LL |     a.iter().sum::<i32>();
    |              ^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:45:7
    |
 LL |     a.sort_unstable();
    |       ^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:46:20
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:49:20
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |                    ^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:61
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:53:61
    |
 LL |     let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
    |                                                             ^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:28
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:28
    |
 LL |     let in_call = Box::new(f32::clamp);
    |                            ^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:53
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:53
    |
 LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
    |                                                     ^^^^^^^^^^
 
 error: use of a disallowed method `futures::stream::select_all`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:31
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
    |                               ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_fn`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:66:5
    |
 LL |     local_fn();
    |     ^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:65:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:5
    |
 LL |     local_mod::f();
    |     ^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Struct::method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:71:7
    |
 LL |     s.method();
    |       ^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:70:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:73:7
    |
 LL |     s.provided_method();
    |       ^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:72:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:75:7
    |
 LL |     s.implemented_method();
    |       ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: use of a disallowed method `conf_disallowed_methods::identity`
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:78:5
+   |
+LL |     identity(());
+   |     ^^^^^^^^
+
+error: use of a disallowed method `conf_disallowed_methods::renamed`
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:80:5
+   |
+LL |     renamed(1);
+   |     ^^^^^^^
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml
index 6cb9e2ef954..08e35017f78 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml
@@ -6,7 +6,7 @@ disallowed-types = [
     "std::thread::Thread",
     "std::time::Instant",
     "std::io::Read",
-    "std::primitive::usize",
+    "usize",
     "bool",
     # can give path and reason with an inline table
     { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr
index 18bc36ca1e3..061cdc7649a 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr
@@ -37,7 +37,7 @@ error: use of a disallowed type `std::io::Read`
 LL | fn trait_obj(_: &dyn std::io::Read) {}
    |                      ^^^^^^^^^^^^^
 
-error: use of a disallowed type `std::primitive::usize`
+error: use of a disallowed type `usize`
   --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:26:33
    |
 LL | fn full_and_single_path_prim(_: usize, _: bool) {}
@@ -49,13 +49,13 @@ error: use of a disallowed type `bool`
 LL | fn full_and_single_path_prim(_: usize, _: bool) {}
    |                                           ^^^^
 
-error: use of a disallowed type `std::primitive::usize`
+error: use of a disallowed type `usize`
   --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:28
    |
 LL | fn const_generics<const C: usize>() {}
    |                            ^^^^^
 
-error: use of a disallowed type `std::primitive::usize`
+error: use of a disallowed type `usize`
   --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:33:24
    |
 LL | struct GenArg<const U: usize>([u8; U]);
@@ -123,7 +123,7 @@ error: use of a disallowed type `proc_macro2::Ident`
 LL |     let _ = syn::Ident::new("", todo!());
    |             ^^^^^^^^^^
 
-error: use of a disallowed type `std::primitive::usize`
+error: use of a disallowed type `usize`
   --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:61:12
    |
 LL |     let _: usize = 64_usize;
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml
index 6d0d732a922..997ed47b71c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml
@@ -1,12 +1,15 @@
-[[disallowed-types]]
-path = "std::result::Result::Err"
-
 [[disallowed-macros]]
 path = "bool"
 
 [[disallowed-methods]]
 path = "std::process::current_exe"
 
+[[disallowed-methods]]
+path = ""
+
+[[disallowed-types]]
+path = "std::result::Result::Err"
+
 # negative test
 
 [[disallowed-methods]]
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs
index c1520382703..ff4eada3900 100644
--- a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs
@@ -1,5 +1,6 @@
 //@error-in-other-file: expected a macro, found a primitive type
-//@error-in-other-file: `std::process::current_exe` does not refer to an existing function
-//@error-in-other-file: expected a type, found a tuple variant
+//@error-in-other-file: `std::process::current_exe` does not refer to a reachable function
+//@error-in-other-file: `` does not refer to a reachable function
+//@error-in-other-file: expected a type, found a variant
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr
index 82550108eba..59a427dc99c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr
@@ -1,23 +1,38 @@
 warning: expected a macro, found a primitive type
-  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1
+  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1
    |
 LL | / [[disallowed-macros]]
 LL | | path = "bool"
    | |_____________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
 
-warning: `std::process::current_exe` does not refer to an existing function
-  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1
+warning: `std::process::current_exe` does not refer to a reachable function
+  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1
    |
 LL | / [[disallowed-methods]]
 LL | | path = "std::process::current_exe"
    | |__________________________________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
 
-warning: expected a type, found a tuple variant
-  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1
+warning: `` does not refer to a reachable function
+  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1
+   |
+LL | / [[disallowed-methods]]
+LL | | path = ""
+   | |_________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
+
+warning: expected a type, found a variant
+  --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:10:1
    |
 LL | / [[disallowed-types]]
 LL | | path = "std::result::Result::Err"
    | |_________________________________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
 
-warning: 3 warnings emitted
+warning: 4 warnings emitted
 
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml
new file mode 100644
index 00000000000..82560cfd5e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml
@@ -0,0 +1,4 @@
+# In the following configuration, "recommendation" should be "reason" or "replacement".
+disallowed-macros = [
+    { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" },
+]
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs
new file mode 100644
index 00000000000..9c770c31f6f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.rs
@@ -0,0 +1,5 @@
+#[rustfmt::skip]
+//@error-in-other-file: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum
+fn main() {
+    panic!();
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr
new file mode 100644
index 00000000000..b564709721d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_config_struct_field/toml_unknown_config_struct_field.stderr
@@ -0,0 +1,8 @@
+error: error reading Clippy's configuration file: data did not match any variant of untagged enum DisallowedPathEnum
+  --> $DIR/tests/ui-toml/toml_unknown_config_struct_field/clippy.toml:3:5
+   |
+LL |     { path = "std::panic", recommendation = "return a `std::result::Result::Error` instead" },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index f2eaa66a4ae..6ee77ebd8ec 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -5,6 +5,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-exact-repetitions
            allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
@@ -57,6 +58,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            max-suggested-slice-pattern-length
            max-trait-bounds
            min-ident-chars-threshold
+           missing-docs-allow-unused
            missing-docs-in-crate-items
            module-item-order-groupings
            module-items-ordered-within-groupings
@@ -97,6 +99,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-exact-repetitions
            allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
@@ -149,6 +152,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            max-suggested-slice-pattern-length
            max-trait-bounds
            min-ident-chars-threshold
+           missing-docs-allow-unused
            missing-docs-in-crate-items
            module-item-order-groupings
            module-items-ordered-within-groupings
@@ -189,6 +193,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-exact-repetitions
            allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
@@ -241,6 +246,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            max-suggested-slice-pattern-length
            max-trait-bounds
            min-ident-chars-threshold
+           missing-docs-allow-unused
            missing-docs-in-crate-items
            module-item-order-groupings
            module-items-ordered-within-groupings
diff --git a/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/clippy.toml
new file mode 100644
index 00000000000..e664256d2a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/clippy.toml
@@ -0,0 +1,10 @@
+# The first two `disallowed-methods` paths should generate warnings, but the third should not.
+
+[[disallowed-methods]]
+path = "regex::Regex::new_"
+
+[[disallowed-methods]]
+path = "regex::Regex_::new"
+
+[[disallowed-methods]]
+path = "regex_::Regex::new"
diff --git a/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs
new file mode 100644
index 00000000000..14f15e73311
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.rs
@@ -0,0 +1,6 @@
+//@error-in-other-file: `regex::Regex::new_` does not refer to a reachable function
+//@error-in-other-file: `regex::Regex_::new` does not refer to a reachable function
+
+extern crate regex;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr
new file mode 100644
index 00000000000..e5fd548b26d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_unloaded_crate/conf_unloaded_crate.stderr
@@ -0,0 +1,20 @@
+warning: `regex::Regex::new_` does not refer to a reachable function
+  --> $DIR/tests/ui-toml/toml_unloaded_crate/clippy.toml:3:1
+   |
+LL | / [[disallowed-methods]]
+LL | | path = "regex::Regex::new_"
+   | |___________________________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
+
+warning: `regex::Regex_::new` does not refer to a reachable function
+  --> $DIR/tests/ui-toml/toml_unloaded_crate/clippy.toml:6:1
+   |
+LL | / [[disallowed-methods]]
+LL | | path = "regex::Regex_::new"
+   | |___________________________^
+   |
+   = help: add `allow-invalid = true` to the entry to suppress this warning
+
+warning: 2 warnings emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs
index 7f93d2071c9..b60cb7632e2 100644
--- a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs
+++ b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs
@@ -12,7 +12,7 @@ fn f2<T>()
 where
     T: Copy + Clone + Sync + Send + ?Sized,
     T: Unpin + PartialEq,
-    //~^ ERROR: this type has already been used as a bound predicate
+    //~^ type_repetition_in_bounds
 {
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr
index c5102c39d1c..ba0f41167a0 100644
--- a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr
+++ b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr
@@ -1,4 +1,4 @@
-error: this type has already been used as a bound predicate
+error: type `T` has already been used as a bound predicate
   --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5
    |
 LL |     T: Unpin + PartialEq,
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
index eed704e82fe..88a27530238 100644
--- a/src/tools/clippy/tests/ui/author.stdout
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -1,8 +1,6 @@
 if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Cast(expr, cast_ty) = init.kind
-    && let TyKind::Path(ref qpath) = cast_ty.kind
-    && match_qpath(qpath, &["char"])
     && let ExprKind::Lit(ref lit) = expr.kind
     && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 54325f9776c..e453299edbc 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -14,8 +14,6 @@ if let ExprKind::Block(block, None) = expr.kind
     && name1.as_str() == "_t"
     && let StmtKind::Semi(e) = block.stmts[2].kind
     && let ExprKind::Unary(UnOp::Neg, inner) = e.kind
-    && let ExprKind::Path(ref qpath) = inner.kind
-    && match_qpath(qpath, &["x"])
     && block.expr.is_none()
 {
     // report your lint here
@@ -25,18 +23,14 @@ if let ExprKind::Block(block, None) = expr.kind
     && let StmtKind::Let(local) = block.stmts[0].kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && let ExprKind::Path(ref qpath) = func.kind
-    && match_qpath(qpath, &["String", "new"])
+    && is_path_diagnostic_item(cx, func, sym::string_new)
     && args.is_empty()
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
     && name.as_str() == "expr"
     && let Some(trailing_expr) = block.expr
     && let ExprKind::Call(func1, args1) = trailing_expr.kind
-    && let ExprKind::Path(ref qpath1) = func1.kind
-    && match_qpath(qpath1, &["drop"])
+    && is_path_diagnostic_item(cx, func1, sym::mem_drop)
     && args1.len() == 1
-    && let ExprKind::Path(ref qpath2) = args1[0].kind
-    && match_qpath(qpath2, &["expr"])
 {
     // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
index 59d4da490fe..2b179d45112 100644
--- a/src/tools/clippy/tests/ui/author/call.stdout
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -1,8 +1,7 @@
 if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && let ExprKind::Path(ref qpath) = func.kind
-    && match_qpath(qpath, &["{{root}}", "std", "cmp", "min"])
+    && is_path_diagnostic_item(cx, func, sym::cmp_min)
     && args.len() == 2
     && let ExprKind::Lit(ref lit) = args[0].kind
     && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
index 8ffdf886202..da359866bff 100644
--- a/src/tools/clippy/tests/ui/author/if.stdout
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -31,10 +31,8 @@ if let StmtKind::Let(local) = stmt.kind
 if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
     && let ExprKind::Let(let_expr) = cond.kind
     && let PatKind::Expr(lit_expr) = let_expr.pat.kind
-    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
+    && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind
     && let LitKind::Bool(true) = lit.node
-    && let ExprKind::Path(ref qpath) = let_expr.init.kind
-    && match_qpath(qpath, &["a"])
     && let ExprKind::Block(block, None) = then.kind
     && block.stmts.is_empty()
     && block.expr.is_none()
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
index a5a8c0304ee..f02ea5bf075 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.stdout
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -1,11 +1,8 @@
 if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && let ExprKind::Path(ref qpath) = func.kind
-    && match_qpath(qpath, &["std", "mem", "transmute"])
+    && is_path_diagnostic_item(cx, func, sym::transmute)
     && args.len() == 1
-    && let ExprKind::Path(ref qpath1) = args[0].kind
-    && match_qpath(qpath1, &["ZPTR"])
     && let PatKind::Wild = local.pat.kind
 {
     // report your lint here
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
index c94eb171f52..79794cec926 100644
--- a/src/tools/clippy/tests/ui/author/loop.stdout
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -14,8 +14,6 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && block.stmts.len() == 1
     && let StmtKind::Let(local) = block.stmts[0].kind
     && let Some(init) = local.init
-    && let ExprKind::Path(ref qpath1) = init.kind
-    && match_qpath(qpath1, &["y"])
     && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
     && name1.as_str() == "z"
     && block.expr.is_none()
@@ -64,8 +62,6 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     // report your lint here
 }
 if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr)
-    && let ExprKind::Path(ref qpath) = condition.kind
-    && match_qpath(qpath, &["a"])
     && let ExprKind::Block(block, None) = body.kind
     && block.stmts.len() == 1
     && let StmtKind::Semi(e) = block.stmts[0].kind
@@ -77,10 +73,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
 }
 if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
     && let PatKind::Expr(lit_expr) = let_pat.kind
-    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
+    && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind
     && let LitKind::Bool(true) = lit.node
-    && let ExprKind::Path(ref qpath) = let_expr.kind
-    && match_qpath(qpath, &["a"])
     && let ExprKind::Block(block, None) = if_then.kind
     && block.stmts.len() == 1
     && let StmtKind::Semi(e) = block.stmts[0].kind
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
index 3186d0cbc27..5f8a4ce2363 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -7,12 +7,10 @@ if let StmtKind::Let(local) = stmt.kind
     && block.stmts.len() == 1
     && let StmtKind::Semi(e) = block.stmts[0].kind
     && let ExprKind::Call(func, args) = e.kind
-    && let ExprKind::Path(ref qpath) = func.kind
-    && match_qpath(qpath, &["$crate", "io", "_print"])
+    && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Call(func1, args1) = args[0].kind
-    && let ExprKind::Path(ref qpath1) = func1.kind
-    && match_qpath(qpath1, &["format_arguments", "new_v1"])
+    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
     && args1.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
     && let ExprKind::Array(elements) = inner.kind
@@ -27,12 +25,9 @@ if let StmtKind::Let(local) = stmt.kind
     && let ExprKind::Array(elements1) = inner1.kind
     && elements1.len() == 1
     && let ExprKind::Call(func2, args2) = elements1[0].kind
-    && let ExprKind::Path(ref qpath2) = func2.kind
-    && match_qpath(qpath2, &["format_argument", "new_display"])
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 1
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
-    && let ExprKind::Path(ref qpath3) = inner2.kind
-    && match_qpath(qpath3, &["x"])
     && block.expr.is_none()
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
     && name.as_str() == "print_text"
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
index 3f9be297c33..ecc25254311 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -17,12 +17,10 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && block1.stmts.len() == 1
     && let StmtKind::Semi(e1) = block1.stmts[0].kind
     && let ExprKind::Call(func, args) = e1.kind
-    && let ExprKind::Path(ref qpath1) = func.kind
-    && match_qpath(qpath1, &["$crate", "io", "_print"])
+    && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Call(func1, args1) = args[0].kind
-    && let ExprKind::Path(ref qpath2) = func1.kind
-    && match_qpath(qpath2, &["format_arguments", "new_v1"])
+    && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
     && args1.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
     && let ExprKind::Array(elements) = inner.kind
@@ -37,12 +35,9 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && let ExprKind::Array(elements1) = inner1.kind
     && elements1.len() == 1
     && let ExprKind::Call(func2, args2) = elements1[0].kind
-    && let ExprKind::Path(ref qpath3) = func2.kind
-    && match_qpath(qpath3, &["format_argument", "new_display"])
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 1
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
-    && let ExprKind::Path(ref qpath4) = inner2.kind
-    && match_qpath(qpath4, &["i"])
     && block1.expr.is_none()
     && block.expr.is_none()
 {
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index acb3b140dfa..9752d7a9f99 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -5,13 +5,13 @@ if let StmtKind::Let(local) = stmt.kind
     && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
     && arms.len() == 3
     && let PatKind::Expr(lit_expr) = arms[0].pat.kind
-    && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
+    && let PatExprKind::Lit { ref lit1, negated } = lit_expr.kind
     && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
     && arms[0].guard.is_none()
     && let ExprKind::Lit(ref lit2) = arms[0].body.kind
     && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
     && let PatKind::Expr(lit_expr1) = arms[1].pat.kind
-    && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
+    && let PatExprKind::Lit { ref lit3, negated1 } = lit_expr1.kind
     && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
     && arms[1].guard.is_none()
     && let ExprKind::Block(block, None) = arms[1].body.kind
@@ -23,8 +23,6 @@ if let StmtKind::Let(local) = stmt.kind
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
     && name.as_str() == "x"
     && let Some(trailing_expr) = block.expr
-    && let ExprKind::Path(ref qpath) = trailing_expr.kind
-    && match_qpath(qpath, &["x"])
     && let PatKind::Wild = arms[2].pat.kind
     && arms[2].guard.is_none()
     && let ExprKind::Lit(ref lit5) = arms[2].body.kind
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
index b66bbccb3cf..1e8fbafd30c 100644
--- a/src/tools/clippy/tests/ui/author/struct.stdout
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -1,5 +1,4 @@
 if let ExprKind::Struct(qpath, fields, None) = expr.kind
-    && match_qpath(qpath, &["Test"])
     && fields.len() == 1
     && fields[0].ident.as_str() == "field"
     && let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind
@@ -20,11 +19,10 @@ if let ExprKind::Struct(qpath, fields, None) = expr.kind
     // report your lint here
 }
 if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
-    && match_qpath(qpath, &["Test"])
     && fields.len() == 1
     && fields[0].ident.as_str() == "field"
     && let PatKind::Expr(lit_expr) = fields[0].pat.kind
-    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
+    && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind
     && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
     && arm.guard.is_none()
     && let ExprKind::Block(block, None) = arm.body.kind
@@ -34,10 +32,9 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
     // report your lint here
 }
 if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
-    && match_qpath(qpath, &["TestTuple"])
     && fields.len() == 1
     && let PatKind::Expr(lit_expr) = fields[0].kind
-    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
+    && let PatExprKind::Lit { ref lit, negated } = lit_expr.kind
     && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
     && arm.guard.is_none()
     && let ExprKind::Block(block, None) = arm.body.kind
@@ -48,8 +45,6 @@ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
 }
 if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind
     && method_name.ident.as_str() == "test"
-    && let ExprKind::Path(ref qpath) = receiver.kind
-    && match_qpath(qpath, &["test_method_call"])
     && args.is_empty()
 {
     // report your lint here
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index e72d6b6cead..4c61c5accd3 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -51,14 +51,14 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
 
     fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
         let arg = sig.inputs.first_mut()?;
-        if let FnArg::Typed(PatType { pat, .. }) = arg {
-            if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
-                if ident == "self" {
-                    return Some(arg);
-                }
-            }
+        if let FnArg::Typed(PatType { pat, .. }) = arg
+            && let Pat::Ident(PatIdent { ident, .. }) = &**pat
+            && ident == "self"
+        {
+            Some(arg)
+        } else {
+            None
         }
-        None
     }
 
     let mut elided = 0;
@@ -66,30 +66,29 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
 
     // Look for methods having arbitrary self type taken by &mut ref
     for inner in &mut item.items {
-        if let ImplItem::Fn(method) = inner {
-            if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
-                if let box Type::Reference(reference) = &mut pat_type.ty {
-                    // Target only unnamed lifetimes
-                    let name = match &reference.lifetime {
-                        Some(lt) if lt.ident == "_" => make_name(elided),
-                        None => make_name(elided),
-                        _ => continue,
-                    };
-                    elided += 1;
-
-                    // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
-                    // In order to avoid adding the dependency, get a default span from a nonexistent token.
-                    // A default span is needed to mark the code as coming from expansion.
-                    let span = Star::default().span();
-
-                    // Replace old lifetime with the named one
-                    let lifetime = Lifetime::new(&name, span);
-                    reference.lifetime = Some(parse_quote!(#lifetime));
-
-                    // Add lifetime to the generics of the method
-                    method.sig.generics.params.push(parse_quote!(#lifetime));
-                }
-            }
+        if let ImplItem::Fn(method) = inner
+            && let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig)
+            && let box Type::Reference(reference) = &mut pat_type.ty
+        {
+            // Target only unnamed lifetimes
+            let name = match &reference.lifetime {
+                Some(lt) if lt.ident == "_" => make_name(elided),
+                None => make_name(elided),
+                _ => continue,
+            };
+            elided += 1;
+
+            // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
+            // In order to avoid adding the dependency, get a default span from a nonexistent token.
+            // A default span is needed to mark the code as coming from expansion.
+            let span = Star::default().span();
+
+            // Replace old lifetime with the named one
+            let lifetime = Lifetime::new(&name, span);
+            reference.lifetime = Some(parse_quote!(#lifetime));
+
+            // Add lifetime to the generics of the method
+            method.sig.generics.params.push(parse_quote!(#lifetime));
         }
     }
 
@@ -129,15 +128,15 @@ pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream
     let mut async_fn = parse_macro_input!(input as syn::ItemFn);
 
     for stmt in &mut async_fn.block.stmts {
-        if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt {
-            if let syn::Expr::Await(syn::ExprAwait { base, await_token, .. }) = scrutinee.as_mut() {
-                let blc = quote_spanned!( await_token.span => {
-                    #[allow(clippy::let_and_return)]
-                    let __pinned = #base;
-                    __pinned
-                });
-                *scrutinee = parse_quote!(#blc);
-            }
+        if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt
+            && let syn::Expr::Await(syn::ExprAwait { base, await_token, .. }) = scrutinee.as_mut()
+        {
+            let blc = quote_spanned!( await_token.span => {
+                #[allow(clippy::let_and_return)]
+                let __pinned = #base;
+                __pinned
+            });
+            *scrutinee = parse_quote!(#blc);
         }
     }
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
index 7a4cc4fa9ee..bb55539617f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![feature(proc_macro_span)]
 #![allow(clippy::needless_if, dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
index e696896538e..6ae5b0cb2f0 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
@@ -4,7 +4,6 @@
 #![allow(
     unused,
     unnecessary_transmutes,
-    clippy::let_and_return,
     clippy::needless_if,
     clippy::missing_transmute_annotations
 )]
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
index 8c8f3249b8a..3fd06062072 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
@@ -4,7 +4,6 @@
 #![allow(
     unused,
     unnecessary_transmutes,
-    clippy::let_and_return,
     clippy::needless_if,
     clippy::missing_transmute_annotations
 )]
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
index 41ff59c683e..282c42a98bf 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
@@ -1,5 +1,5 @@
 error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
-  --> tests/ui/blocks_in_conditions.rs:31:5
+  --> tests/ui/blocks_in_conditions.rs:30:5
    |
 LL | /     if {
 LL | |
@@ -20,13 +20,13 @@ LL ~     }; if res {
    |
 
 error: omit braces around single expression condition
-  --> tests/ui/blocks_in_conditions.rs:43:8
+  --> tests/ui/blocks_in_conditions.rs:42:8
    |
 LL |     if { true } { 6 } else { 10 }
    |        ^^^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> tests/ui/blocks_in_conditions.rs:49:8
+  --> tests/ui/blocks_in_conditions.rs:48:8
    |
 LL |     if true && x == 3 { 6 } else { 10 }
    |        ^^^^^^^^^^^^^^ help: try: `x == 3`
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
index ed6141244b4..7fa7c016f93 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
index 3f1f1c766e4..2295d6f1362 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -1,4 +1,3 @@
-#![feature(let_chains)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
index 94089bc6dc8..e4ae5730414 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -1,5 +1,5 @@
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:14:5
+  --> tests/ui/bool_to_int_with_if.rs:13:5
    |
 LL | /     if a {
 LL | |
@@ -14,7 +14,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::bool_to_int_with_if)]`
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:20:5
+  --> tests/ui/bool_to_int_with_if.rs:19:5
    |
 LL | /     if a {
 LL | |
@@ -27,7 +27,7 @@ LL | |     };
    = note: `!a as i32` or `(!a).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:26:5
+  --> tests/ui/bool_to_int_with_if.rs:25:5
    |
 LL | /     if !a {
 LL | |
@@ -40,7 +40,7 @@ LL | |     };
    = note: `!a as i32` or `(!a).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:32:5
+  --> tests/ui/bool_to_int_with_if.rs:31:5
    |
 LL | /     if a || b {
 LL | |
@@ -53,7 +53,7 @@ LL | |     };
    = note: `(a || b) as i32` or `(a || b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:38:5
+  --> tests/ui/bool_to_int_with_if.rs:37:5
    |
 LL | /     if cond(a, b) {
 LL | |
@@ -66,7 +66,7 @@ LL | |     };
    = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:44:5
+  --> tests/ui/bool_to_int_with_if.rs:43:5
    |
 LL | /     if x + y < 4 {
 LL | |
@@ -79,7 +79,7 @@ LL | |     };
    = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:54:12
+  --> tests/ui/bool_to_int_with_if.rs:53:12
    |
 LL |       } else if b {
    |  ____________^
@@ -93,7 +93,7 @@ LL | |     };
    = note: `b as i32` or `b.into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:64:12
+  --> tests/ui/bool_to_int_with_if.rs:63:12
    |
 LL |       } else if b {
    |  ____________^
@@ -107,7 +107,7 @@ LL | |     };
    = note: `!b as i32` or `(!b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:130:5
+  --> tests/ui/bool_to_int_with_if.rs:129:5
    |
 LL |     if a { 1 } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
@@ -115,7 +115,7 @@ LL |     if a { 1 } else { 0 }
    = note: `a as u8` or `a.into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:174:13
+  --> tests/ui/bool_to_int_with_if.rs:173:13
    |
 LL |     let _ = if dbg!(4 > 0) { 1 } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))`
@@ -123,7 +123,7 @@ LL |     let _ = if dbg!(4 > 0) { 1 } else { 0 };
    = note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> tests/ui/bool_to_int_with_if.rs:177:18
+  --> tests/ui/bool_to_int_with_if.rs:176:18
    |
 LL |     let _ = dbg!(if 4 > 0 { 1 } else { 0 });
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)`
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 4101897d380..ba0d36d85fe 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -188,6 +188,91 @@ fn issue11371() {
     }
 }
 
+fn gen_option() -> Option<()> {
+    Some(())
+    // Or None
+}
+
+fn gen_result() -> Result<(), ()> {
+    Ok(())
+    // Or Err(())
+}
+
+fn issue14725() {
+    let option = Some(());
+
+    if option.is_some() {
+        let _ = option.as_ref().unwrap();
+        //~^ unnecessary_unwrap
+    } else {
+        let _ = option.as_ref().unwrap();
+        //~^ panicking_unwrap
+    }
+
+    let result = Ok::<(), ()>(());
+
+    if result.is_ok() {
+        let _y = 1;
+        result.as_ref().unwrap();
+        //~^ unnecessary_unwrap
+    } else {
+        let _y = 1;
+        result.as_ref().unwrap();
+        //~^ panicking_unwrap
+    }
+
+    let mut option = Some(());
+    if option.is_some() {
+        option = gen_option();
+        option.as_mut().unwrap();
+    } else {
+        option = gen_option();
+        option.as_mut().unwrap();
+    }
+
+    let mut result = Ok::<(), ()>(());
+    if result.is_ok() {
+        result = gen_result();
+        result.as_mut().unwrap();
+    } else {
+        result = gen_result();
+        result.as_mut().unwrap();
+    }
+}
+
+fn issue14763(x: Option<String>, r: Result<(), ()>) {
+    _ = || {
+        if x.is_some() {
+            _ = x.unwrap();
+            //~^ unnecessary_unwrap
+        } else {
+            _ = x.unwrap();
+            //~^ panicking_unwrap
+        }
+    };
+    _ = || {
+        if r.is_ok() {
+            _ = r.as_ref().unwrap();
+            //~^ unnecessary_unwrap
+        } else {
+            _ = r.as_ref().unwrap();
+            //~^ panicking_unwrap
+        }
+    };
+}
+
+const ISSUE14763: fn(Option<String>) = |x| {
+    _ = || {
+        if x.is_some() {
+            _ = x.unwrap();
+            //~^ unnecessary_unwrap
+        } else {
+            _ = x.unwrap();
+            //~^ panicking_unwrap
+        }
+    }
+};
+
 fn check_expect() {
     let x = Some(());
     if x.is_some() {
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index ad3c420270c..a4bf0099244 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -236,6 +236,92 @@ LL |     if result.is_ok() {
 LL |         result.as_mut().unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: called `unwrap` on `option` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:205:17
+   |
+LL |     if option.is_some() {
+   |     ------------------- help: try: `if let Some(<item>) = &option`
+LL |         let _ = option.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:208:17
+   |
+LL |     if option.is_some() {
+   |        ---------------- because of this check
+...
+LL |         let _ = option.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `result` after checking its variant with `is_ok`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:216:9
+   |
+LL |     if result.is_ok() {
+   |     ----------------- help: try: `if let Ok(<item>) = &result`
+LL |         let _y = 1;
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:220:9
+   |
+LL |     if result.is_ok() {
+   |        -------------- because of this check
+...
+LL |         result.as_ref().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `x` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:246:17
+   |
+LL |         if x.is_some() {
+   |         -------------- help: try: `if let Some(<item>) = x`
+LL |             _ = x.unwrap();
+   |                 ^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:249:17
+   |
+LL |         if x.is_some() {
+   |            ----------- because of this check
+...
+LL |             _ = x.unwrap();
+   |                 ^^^^^^^^^^
+
+error: called `unwrap` on `r` after checking its variant with `is_ok`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:255:17
+   |
+LL |         if r.is_ok() {
+   |         ------------ help: try: `if let Ok(<item>) = &r`
+LL |             _ = r.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:258:17
+   |
+LL |         if r.is_ok() {
+   |            --------- because of this check
+...
+LL |             _ = r.as_ref().unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^
+
+error: called `unwrap` on `x` after checking its variant with `is_some`
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:267:17
+   |
+LL |         if x.is_some() {
+   |         -------------- help: try: `if let Some(<item>) = x`
+LL |             _ = x.unwrap();
+   |                 ^^^^^^^^^^
+
+error: this call to `unwrap()` will always panic
+  --> tests/ui/checked_unwrap/simple_conditionals.rs:270:17
+   |
+LL |         if x.is_some() {
+   |            ----------- because of this check
+...
+LL |             _ = x.unwrap();
+   |                 ^^^^^^^^^^
+
 error: creating a shared reference to mutable static
   --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12
    |
@@ -246,5 +332,5 @@ LL |         if X.is_some() {
    = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
    = note: `#[deny(static_mut_refs)]` on by default
 
-error: aborting due to 26 previous errors
+error: aborting due to 36 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.fixed b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.fixed
new file mode 100644
index 00000000000..818c6e23259
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.fixed
@@ -0,0 +1,64 @@
+#![warn(clippy::cloned_ref_to_slice_refs)]
+
+#[derive(Clone)]
+struct Data;
+
+fn main() {
+    {
+        let data = Data;
+        let data_ref = &data;
+        let _ = std::slice::from_ref(data_ref); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    {
+        let _ = std::slice::from_ref(&Data); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    {
+        #[derive(Clone)]
+        struct Point(i32, i32);
+
+        let _ = std::slice::from_ref(&Point(0, 0)); //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    // the string was cloned with the intention to not mutate
+    {
+        struct BetterString(String);
+
+        let mut message = String::from("good");
+        let sender = BetterString(message.clone());
+
+        message.push_str("bye!");
+
+        println!("{} {}", message, sender.0)
+    }
+
+    // the string was cloned with the intention to not mutate
+    {
+        let mut x = String::from("Hello");
+        let r = &[x.clone()];
+        x.push('!');
+        println!("r = `{}', x = `{x}'", r[0]);
+    }
+
+    // mutable borrows may have the intention to clone
+    {
+        let data = Data;
+        let data_ref = &data;
+        let _ = &mut [data_ref.clone()];
+    }
+
+    // `T::clone` is used to denote a clone with side effects
+    {
+        use std::sync::Arc;
+        let data = Arc::new(Data);
+        let _ = &[Arc::clone(&data)];
+    }
+
+    // slices with multiple members can only be made from a singular reference
+    {
+        let data_1 = Data;
+        let data_2 = Data;
+        let _ = &[data_1.clone(), data_2.clone()];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.rs b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.rs
new file mode 100644
index 00000000000..9517dbfd156
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.rs
@@ -0,0 +1,64 @@
+#![warn(clippy::cloned_ref_to_slice_refs)]
+
+#[derive(Clone)]
+struct Data;
+
+fn main() {
+    {
+        let data = Data;
+        let data_ref = &data;
+        let _ = &[data_ref.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    {
+        let _ = &[Data.clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    {
+        #[derive(Clone)]
+        struct Point(i32, i32);
+
+        let _ = &[Point(0, 0).clone()]; //~ ERROR: this call to `clone` can be replaced with `std::slice::from_ref`
+    }
+
+    // the string was cloned with the intention to not mutate
+    {
+        struct BetterString(String);
+
+        let mut message = String::from("good");
+        let sender = BetterString(message.clone());
+
+        message.push_str("bye!");
+
+        println!("{} {}", message, sender.0)
+    }
+
+    // the string was cloned with the intention to not mutate
+    {
+        let mut x = String::from("Hello");
+        let r = &[x.clone()];
+        x.push('!');
+        println!("r = `{}', x = `{x}'", r[0]);
+    }
+
+    // mutable borrows may have the intention to clone
+    {
+        let data = Data;
+        let data_ref = &data;
+        let _ = &mut [data_ref.clone()];
+    }
+
+    // `T::clone` is used to denote a clone with side effects
+    {
+        use std::sync::Arc;
+        let data = Arc::new(Data);
+        let _ = &[Arc::clone(&data)];
+    }
+
+    // slices with multiple members can only be made from a singular reference
+    {
+        let data_1 = Data;
+        let data_2 = Data;
+        let _ = &[data_1.clone(), data_2.clone()];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.stderr b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.stderr
new file mode 100644
index 00000000000..6a31d878239
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cloned_ref_to_slice_refs.stderr
@@ -0,0 +1,23 @@
+error: this call to `clone` can be replaced with `std::slice::from_ref`
+  --> tests/ui/cloned_ref_to_slice_refs.rs:10:17
+   |
+LL |         let _ = &[data_ref.clone()];
+   |                 ^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(data_ref)`
+   |
+   = note: `-D clippy::cloned-ref-to-slice-refs` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::cloned_ref_to_slice_refs)]`
+
+error: this call to `clone` can be replaced with `std::slice::from_ref`
+  --> tests/ui/cloned_ref_to_slice_refs.rs:14:17
+   |
+LL |         let _ = &[Data.clone()];
+   |                 ^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Data)`
+
+error: this call to `clone` can be replaced with `std::slice::from_ref`
+  --> tests/ui/cloned_ref_to_slice_refs.rs:21:17
+   |
+LL |         let _ = &[Point(0, 0).clone()];
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::slice::from_ref(&Point(0, 0))`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index e1ceb04f9cb..b553182a445 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -101,27 +101,8 @@ fn main() {
         }
     }
 
-    // Test behavior wrt. `let_chains`.
-    // None of the cases below should be collapsed.
     fn truth() -> bool { true }
 
-    // Prefix:
-    if let 0 = 1 {
-        if truth() {}
-    }
-
-    // Suffix:
-    if truth() {
-        if let 0 = 1 {}
-    }
-
-    // Midfix:
-    if truth() {
-        if let 0 = 1 {
-            if truth() {}
-        }
-    }
-
     // Fix #5962
     if matches!(true, true)
         && matches!(true, true) {}
@@ -162,3 +143,14 @@ fn layout_check() -> u32 {
     ; 3
     //~^^^^^ collapsible_if
 }
+
+fn issue14722() {
+    let x = if true {
+        Some(1)
+    } else {
+        if true {
+            println!("Some debug information");
+        };
+        None
+    };
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index 0b996dca22e..f5998457ca6 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -108,27 +108,8 @@ fn main() {
         }
     }
 
-    // Test behavior wrt. `let_chains`.
-    // None of the cases below should be collapsed.
     fn truth() -> bool { true }
 
-    // Prefix:
-    if let 0 = 1 {
-        if truth() {}
-    }
-
-    // Suffix:
-    if truth() {
-        if let 0 = 1 {}
-    }
-
-    // Midfix:
-    if truth() {
-        if let 0 = 1 {
-            if truth() {}
-        }
-    }
-
     // Fix #5962
     if matches!(true, true) {
         if matches!(true, true) {}
@@ -172,3 +153,14 @@ fn layout_check() -> u32 {
     }; 3
     //~^^^^^ collapsible_if
 }
+
+fn issue14722() {
+    let x = if true {
+        Some(1)
+    } else {
+        if true {
+            println!("Some debug information");
+        };
+        None
+    };
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr
index 53281146239..32c6b019403 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_if.stderr
@@ -127,7 +127,7 @@ LL ~         }
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if.rs:133:5
+  --> tests/ui/collapsible_if.rs:114:5
    |
 LL | /     if matches!(true, true) {
 LL | |         if matches!(true, true) {}
@@ -141,7 +141,7 @@ LL ~         && matches!(true, true) {}
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if.rs:139:5
+  --> tests/ui/collapsible_if.rs:120:5
    |
 LL | /     if matches!(true, true) && truth() {
 LL | |         if matches!(true, true) {}
@@ -155,7 +155,7 @@ LL ~         && matches!(true, true) {}
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if.rs:151:5
+  --> tests/ui/collapsible_if.rs:132:5
    |
 LL | /     if true {
 LL | |         if true {
@@ -173,7 +173,7 @@ LL ~         }
    |
 
 error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if.rs:168:5
+  --> tests/ui/collapsible_if.rs:149:5
    |
 LL | /     if true {
 LL | |         if true {
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.fixed b/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.fixed
new file mode 100644
index 00000000000..ad08c21ba9e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.fixed
@@ -0,0 +1,68 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+//@[edition2021] check-pass
+
+#![warn(clippy::collapsible_if)]
+
+fn main() {
+    if let Some(a) = Some(3) {
+        // with comment, so do not lint
+        if let Some(b) = Some(4) {
+            let _ = a + b;
+        }
+    }
+
+    //~[edition2024]v collapsible_if
+    if let Some(a) = Some(3)
+        && let Some(b) = Some(4) {
+            let _ = a + b;
+        }
+
+    //~[edition2024]v collapsible_if
+    if let Some(a) = Some(3)
+        && a + 1 == 4 {
+            let _ = a;
+        }
+
+    //~[edition2024]v collapsible_if
+    if Some(3) == Some(4).map(|x| x - 1)
+        && let Some(b) = Some(4) {
+            let _ = b;
+        }
+
+    fn truth() -> bool {
+        true
+    }
+
+    // Prefix:
+    //~[edition2024]v collapsible_if
+    if let 0 = 1
+        && truth() {}
+
+    // Suffix:
+    //~[edition2024]v collapsible_if
+    if truth()
+        && let 0 = 1 {}
+
+    // Midfix:
+    //~[edition2024]vvv collapsible_if
+    //~[edition2024]v collapsible_if
+    if truth()
+        && let 0 = 1
+            && truth() {}
+}
+
+#[clippy::msrv = "1.87.0"]
+fn msrv_1_87() {
+    if let 0 = 1 {
+        if true {}
+    }
+}
+
+#[clippy::msrv = "1.88.0"]
+fn msrv_1_88() {
+    //~[edition2024]v collapsible_if
+    if let 0 = 1
+        && true {}
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.stderr b/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.stderr
new file mode 100644
index 00000000000..b0aa3cecadb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.edition2024.stderr
@@ -0,0 +1,132 @@
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:17:5
+   |
+LL | /     if let Some(a) = Some(3) {
+LL | |         if let Some(b) = Some(4) {
+LL | |             let _ = a + b;
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::collapsible-if` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
+help: collapse nested if block
+   |
+LL ~     if let Some(a) = Some(3)
+LL ~         && let Some(b) = Some(4) {
+LL |             let _ = a + b;
+LL ~         }
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:24:5
+   |
+LL | /     if let Some(a) = Some(3) {
+LL | |         if a + 1 == 4 {
+LL | |             let _ = a;
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if let Some(a) = Some(3)
+LL ~         && a + 1 == 4 {
+LL |             let _ = a;
+LL ~         }
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:31:5
+   |
+LL | /     if Some(3) == Some(4).map(|x| x - 1) {
+LL | |         if let Some(b) = Some(4) {
+LL | |             let _ = b;
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if Some(3) == Some(4).map(|x| x - 1)
+LL ~         && let Some(b) = Some(4) {
+LL |             let _ = b;
+LL ~         }
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:43:5
+   |
+LL | /     if let 0 = 1 {
+LL | |         if truth() {}
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if let 0 = 1
+LL ~         && truth() {}
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:49:5
+   |
+LL | /     if truth() {
+LL | |         if let 0 = 1 {}
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if truth()
+LL ~         && let 0 = 1 {}
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:56:5
+   |
+LL | /     if truth() {
+LL | |         if let 0 = 1 {
+LL | |             if truth() {}
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if truth()
+LL ~         && let 0 = 1 {
+LL |             if truth() {}
+LL ~         }
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:57:9
+   |
+LL | /         if let 0 = 1 {
+LL | |             if truth() {}
+LL | |         }
+   | |_________^
+   |
+help: collapse nested if block
+   |
+LL ~         if let 0 = 1
+LL ~             && truth() {}
+   |
+
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if_let_chains.rs:73:5
+   |
+LL | /     if let 0 = 1 {
+LL | |         if true {}
+LL | |     }
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if let 0 = 1
+LL ~         && true {}
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed b/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed
deleted file mode 100644
index 3dd9498a4c9..00000000000
--- a/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(let_chains)]
-#![warn(clippy::collapsible_if)]
-
-fn main() {
-    if let Some(a) = Some(3) {
-        // with comment, so do not lint
-        if let Some(b) = Some(4) {
-            let _ = a + b;
-        }
-    }
-
-    if let Some(a) = Some(3)
-        && let Some(b) = Some(4) {
-            let _ = a + b;
-        }
-    //~^^^^^ collapsible_if
-
-    if let Some(a) = Some(3)
-        && a + 1 == 4 {
-            let _ = a;
-        }
-    //~^^^^^ collapsible_if
-
-    if Some(3) == Some(4).map(|x| x - 1)
-        && let Some(b) = Some(4) {
-            let _ = b;
-        }
-    //~^^^^^ collapsible_if
-}
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs b/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs
index 064b9a0be48..b2e88b1a556 100644
--- a/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs
@@ -1,4 +1,8 @@
-#![feature(let_chains)]
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+//@[edition2021] check-pass
+
 #![warn(clippy::collapsible_if)]
 
 fn main() {
@@ -9,24 +13,64 @@ fn main() {
         }
     }
 
+    //~[edition2024]v collapsible_if
     if let Some(a) = Some(3) {
         if let Some(b) = Some(4) {
             let _ = a + b;
         }
     }
-    //~^^^^^ collapsible_if
 
+    //~[edition2024]v collapsible_if
     if let Some(a) = Some(3) {
         if a + 1 == 4 {
             let _ = a;
         }
     }
-    //~^^^^^ collapsible_if
 
+    //~[edition2024]v collapsible_if
     if Some(3) == Some(4).map(|x| x - 1) {
         if let Some(b) = Some(4) {
             let _ = b;
         }
     }
-    //~^^^^^ collapsible_if
+
+    fn truth() -> bool {
+        true
+    }
+
+    // Prefix:
+    //~[edition2024]v collapsible_if
+    if let 0 = 1 {
+        if truth() {}
+    }
+
+    // Suffix:
+    //~[edition2024]v collapsible_if
+    if truth() {
+        if let 0 = 1 {}
+    }
+
+    // Midfix:
+    //~[edition2024]vvv collapsible_if
+    //~[edition2024]v collapsible_if
+    if truth() {
+        if let 0 = 1 {
+            if truth() {}
+        }
+    }
+}
+
+#[clippy::msrv = "1.87.0"]
+fn msrv_1_87() {
+    if let 0 = 1 {
+        if true {}
+    }
+}
+
+#[clippy::msrv = "1.88.0"]
+fn msrv_1_88() {
+    //~[edition2024]v collapsible_if
+    if let 0 = 1 {
+        if true {}
+    }
 }
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr b/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr
deleted file mode 100644
index 64a88114c47..00000000000
--- a/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr
+++ /dev/null
@@ -1,58 +0,0 @@
-error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if_let_chains.rs:12:5
-   |
-LL | /     if let Some(a) = Some(3) {
-LL | |         if let Some(b) = Some(4) {
-LL | |             let _ = a + b;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: `-D clippy::collapsible-if` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
-help: collapse nested if block
-   |
-LL ~     if let Some(a) = Some(3)
-LL ~         && let Some(b) = Some(4) {
-LL |             let _ = a + b;
-LL ~         }
-   |
-
-error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if_let_chains.rs:19:5
-   |
-LL | /     if let Some(a) = Some(3) {
-LL | |         if a + 1 == 4 {
-LL | |             let _ = a;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-help: collapse nested if block
-   |
-LL ~     if let Some(a) = Some(3)
-LL ~         && a + 1 == 4 {
-LL |             let _ = a;
-LL ~         }
-   |
-
-error: this `if` statement can be collapsed
-  --> tests/ui/collapsible_if_let_chains.rs:26:5
-   |
-LL | /     if Some(3) == Some(4).map(|x| x - 1) {
-LL | |         if let Some(b) = Some(4) {
-LL | |             let _ = b;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-help: collapse nested if block
-   |
-LL ~     if Some(3) == Some(4).map(|x| x - 1)
-LL ~         && let Some(b) = Some(4) {
-LL |             let _ = b;
-LL ~         }
-   |
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 55ef5584495..71b82040ff6 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::collapsible_match)]
 #![allow(
+    clippy::collapsible_if,
     clippy::equatable_if_let,
     clippy::needless_return,
     clippy::no_effect,
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index 5294a9d6975..c290d84ec29 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -1,5 +1,5 @@
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:14:20
+  --> tests/ui/collapsible_match.rs:15:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -10,7 +10,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:14:12
+  --> tests/ui/collapsible_match.rs:15:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -21,7 +21,7 @@ LL |             Some(n) => foo(n),
    = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]`
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:24:20
+  --> tests/ui/collapsible_match.rs:25:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -32,7 +32,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:24:12
+  --> tests/ui/collapsible_match.rs:25:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -41,7 +41,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:34:9
+  --> tests/ui/collapsible_match.rs:35:9
    |
 LL | /         if let Some(n) = val {
 LL | |
@@ -51,7 +51,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:33:15
+  --> tests/ui/collapsible_match.rs:34:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -59,7 +59,7 @@ LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:43:9
+  --> tests/ui/collapsible_match.rs:44:9
    |
 LL | /         if let Some(n) = val {
 LL | |
@@ -71,7 +71,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:42:15
+  --> tests/ui/collapsible_match.rs:43:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -79,7 +79,7 @@ LL |         if let Some(n) = val {
    |                ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:56:9
+  --> tests/ui/collapsible_match.rs:57:9
    |
 LL | /         match val {
 LL | |
@@ -89,7 +89,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:55:15
+  --> tests/ui/collapsible_match.rs:56:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -98,7 +98,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:66:13
+  --> tests/ui/collapsible_match.rs:67:13
    |
 LL | /             if let Some(n) = val {
 LL | |
@@ -108,7 +108,7 @@ LL | |             }
    | |_____________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:65:12
+  --> tests/ui/collapsible_match.rs:66:12
    |
 LL |         Ok(val) => {
    |            ^^^ replace this binding
@@ -116,7 +116,7 @@ LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:77:9
+  --> tests/ui/collapsible_match.rs:78:9
    |
 LL | /         match val {
 LL | |
@@ -126,7 +126,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:76:15
+  --> tests/ui/collapsible_match.rs:77:15
    |
 LL |     if let Ok(val) = res_opt {
    |               ^^^ replace this binding
@@ -135,7 +135,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:89:13
+  --> tests/ui/collapsible_match.rs:90:13
    |
 LL | /             if let Some(n) = val {
 LL | |
@@ -147,7 +147,7 @@ LL | |             }
    | |_____________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:88:12
+  --> tests/ui/collapsible_match.rs:89:12
    |
 LL |         Ok(val) => {
    |            ^^^ replace this binding
@@ -155,7 +155,7 @@ LL |             if let Some(n) = val {
    |                    ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:102:20
+  --> tests/ui/collapsible_match.rs:103:20
    |
 LL |           Ok(val) => match val {
    |  ____________________^
@@ -166,7 +166,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:102:12
+  --> tests/ui/collapsible_match.rs:103:12
    |
 LL |         Ok(val) => match val {
    |            ^^^ replace this binding
@@ -175,7 +175,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:112:22
+  --> tests/ui/collapsible_match.rs:113:22
    |
 LL |           Some(val) => match val {
    |  ______________________^
@@ -186,7 +186,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:112:14
+  --> tests/ui/collapsible_match.rs:113:14
    |
 LL |         Some(val) => match val {
    |              ^^^ replace this binding
@@ -195,7 +195,7 @@ LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `match`
-  --> tests/ui/collapsible_match.rs:256:22
+  --> tests/ui/collapsible_match.rs:257:22
    |
 LL |           Some(val) => match val {
    |  ______________________^
@@ -206,7 +206,7 @@ LL | |         },
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:256:14
+  --> tests/ui/collapsible_match.rs:257:14
    |
 LL |         Some(val) => match val {
    |              ^^^ replace this binding
@@ -215,7 +215,7 @@ LL |             E::A(val) | E::B(val) => foo(val),
    |             ^^^^^^^^^^^^^^^^^^^^^ with this pattern
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:288:9
+  --> tests/ui/collapsible_match.rs:289:9
    |
 LL | /         if let Some(u) = a {
 LL | |
@@ -225,7 +225,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:287:27
+  --> tests/ui/collapsible_match.rs:288:27
    |
 LL |     if let Issue9647::A { a, .. } = x {
    |                           ^ replace this binding
@@ -233,7 +233,7 @@ LL |         if let Some(u) = a {
    |                ^^^^^^^ with this pattern, prefixed by `a`:
 
 error: this `if let` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:298:9
+  --> tests/ui/collapsible_match.rs:299:9
    |
 LL | /         if let Some(u) = a {
 LL | |
@@ -243,7 +243,7 @@ LL | |         }
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:297:35
+  --> tests/ui/collapsible_match.rs:298:35
    |
 LL |     if let Issue9647::A { a: Some(a), .. } = x {
    |                                   ^ replace this binding
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
index dfbb6168384..7a71829dd62 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -1,6 +1,5 @@
 #![warn(clippy::comparison_to_empty)]
 #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
-#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
index 61cdb2bbe9f..5d213a09e81 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.rs
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -1,6 +1,5 @@
 #![warn(clippy::comparison_to_empty)]
 #![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
-#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
index 00a50430a3e..deb3e938878 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:8:13
+  --> tests/ui/comparison_to_empty.rs:7:13
    |
 LL |     let _ = s == "";
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -8,73 +8,73 @@ LL |     let _ = s == "";
    = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:10:13
+  --> tests/ui/comparison_to_empty.rs:9:13
    |
 LL |     let _ = s != "";
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:14:13
+  --> tests/ui/comparison_to_empty.rs:13:13
    |
 LL |     let _ = v == [];
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:16:13
+  --> tests/ui/comparison_to_empty.rs:15:13
    |
 LL |     let _ = v != [];
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:18:8
+  --> tests/ui/comparison_to_empty.rs:17:8
    |
 LL |     if let [] = &*v {}
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:21:8
+  --> tests/ui/comparison_to_empty.rs:20:8
    |
 LL |     if let [] = s {}
    |        ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:23:8
+  --> tests/ui/comparison_to_empty.rs:22:8
    |
 LL |     if let [] = &*s {}
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice using `if let`
-  --> tests/ui/comparison_to_empty.rs:25:8
+  --> tests/ui/comparison_to_empty.rs:24:8
    |
 LL |     if let [] = &*s
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:27:12
+  --> tests/ui/comparison_to_empty.rs:26:12
    |
 LL |         && s == []
    |            ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:48:13
+  --> tests/ui/comparison_to_empty.rs:47:13
    |
 LL |     let _ = s.eq("");
    |             ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:50:13
+  --> tests/ui/comparison_to_empty.rs:49:13
    |
 LL |     let _ = s.ne("");
    |             ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:53:13
+  --> tests/ui/comparison_to_empty.rs:52:13
    |
 LL |     let _ = v.eq(&[]);
    |             ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/comparison_to_empty.rs:55:13
+  --> tests/ui/comparison_to_empty.rs:54:13
    |
 LL |     let _ = v.ne(&[]);
    |             ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
diff --git a/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.fixed b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.fixed
new file mode 100644
index 00000000000..e698b99edd5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.fixed
@@ -0,0 +1,14 @@
+#![feature(float_minimum_maximum)]
+#![warn(clippy::confusing_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::MIN as usize; //~ confusing_method_to_numeric_cast
+
+    let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MAX as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::MIN as usize; //~ confusing_method_to_numeric_cast
+}
diff --git a/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.rs b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.rs
new file mode 100644
index 00000000000..ef65c21563d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.rs
@@ -0,0 +1,14 @@
+#![feature(float_minimum_maximum)]
+#![warn(clippy::confusing_method_to_numeric_cast)]
+
+fn main() {
+    let _ = u16::max as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::min as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::max_value as usize; //~ confusing_method_to_numeric_cast
+    let _ = u16::min_value as usize; //~ confusing_method_to_numeric_cast
+
+    let _ = f32::maximum as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::max as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::minimum as usize; //~ confusing_method_to_numeric_cast
+    let _ = f32::min as usize; //~ confusing_method_to_numeric_cast
+}
diff --git a/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.stderr b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.stderr
new file mode 100644
index 00000000000..ba90df2059a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/confusing_method_to_numeric_cast.stderr
@@ -0,0 +1,100 @@
+error: casting function pointer `u16::max` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:5:13
+   |
+LL |     let _ = u16::max as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::confusing-method-to-numeric-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::confusing_method_to_numeric_cast)]`
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::max as usize;
+LL +     let _ = u16::MAX as usize;
+   |
+
+error: casting function pointer `u16::min` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:6:13
+   |
+LL |     let _ = u16::min as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::min as usize;
+LL +     let _ = u16::MIN as usize;
+   |
+
+error: casting function pointer `u16::max_value` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:7:13
+   |
+LL |     let _ = u16::max_value as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::max_value as usize;
+LL +     let _ = u16::MAX as usize;
+   |
+
+error: casting function pointer `u16::min_value` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:8:13
+   |
+LL |     let _ = u16::min_value as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = u16::min_value as usize;
+LL +     let _ = u16::MIN as usize;
+   |
+
+error: casting function pointer `f32::maximum` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:10:13
+   |
+LL |     let _ = f32::maximum as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::maximum as usize;
+LL +     let _ = f32::MAX as usize;
+   |
+
+error: casting function pointer `f32::max` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:11:13
+   |
+LL |     let _ = f32::max as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::max as usize;
+LL +     let _ = f32::MAX as usize;
+   |
+
+error: casting function pointer `f32::minimum` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:12:13
+   |
+LL |     let _ = f32::minimum as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::minimum as usize;
+LL +     let _ = f32::MIN as usize;
+   |
+
+error: casting function pointer `f32::min` to `usize`
+  --> tests/ui/confusing_method_to_numeric_cast.rs:13:13
+   |
+LL |     let _ = f32::min as usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: did you mean to use the associated constant?
+   |
+LL -     let _ = f32::min as usize;
+LL +     let _ = f32::MIN as usize;
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.fixed b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.fixed
new file mode 100644
index 00000000000..9c85c4b8464
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.fixed
@@ -0,0 +1,13 @@
+//@compile-flags: -Z validate-mir
+#![warn(clippy::missing_const_for_fn)]
+
+static BLOCK_FN_DEF: fn(usize) -> usize = {
+    //~v missing_const_for_fn
+    const fn foo(a: usize) -> usize {
+        a + 10
+    }
+    foo
+};
+struct X;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.rs b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.rs
new file mode 100644
index 00000000000..6519be61256
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.rs
@@ -0,0 +1,13 @@
+//@compile-flags: -Z validate-mir
+#![warn(clippy::missing_const_for_fn)]
+
+static BLOCK_FN_DEF: fn(usize) -> usize = {
+    //~v missing_const_for_fn
+    fn foo(a: usize) -> usize {
+        a + 10
+    }
+    foo
+};
+struct X;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.stderr b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.stderr
new file mode 100644
index 00000000000..a407376d0b9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/missing_const_for_fn_14774.stderr
@@ -0,0 +1,17 @@
+error: this could be a `const fn`
+  --> tests/ui/crashes/missing_const_for_fn_14774.rs:6:5
+   |
+LL | /     fn foo(a: usize) -> usize {
+LL | |         a + 10
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
+help: make the function `const`
+   |
+LL |     const fn foo(a: usize) -> usize {
+   |     +++++
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
index 2ce0c04c301..be31ee5fb48 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
@@ -84,6 +84,19 @@ fn issue_14139() {
 }
 
 fn drop_order() {
+    struct DropDeIterator(std::vec::IntoIter<S>);
+    impl Iterator for DropDeIterator {
+        type Item = S;
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+    }
+    impl DoubleEndedIterator for DropDeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+
     struct S(&'static str);
     impl std::ops::Drop for S {
         fn drop(&mut self) {
@@ -92,7 +105,7 @@ fn drop_order() {
     }
 
     let v = vec![S("one"), S("two"), S("three")];
-    let mut v = v.into_iter();
+    let mut v = DropDeIterator(v.into_iter());
     println!("Last element is {}", v.next_back().unwrap().0);
     //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
     println!("Done");
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
index a4eb9b3337b..30864e15bce 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
@@ -84,6 +84,19 @@ fn issue_14139() {
 }
 
 fn drop_order() {
+    struct DropDeIterator(std::vec::IntoIter<S>);
+    impl Iterator for DropDeIterator {
+        type Item = S;
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+    }
+    impl DoubleEndedIterator for DropDeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+
     struct S(&'static str);
     impl std::ops::Drop for S {
         fn drop(&mut self) {
@@ -92,7 +105,7 @@ fn drop_order() {
     }
 
     let v = vec![S("one"), S("two"), S("three")];
-    let v = v.into_iter();
+    let v = DropDeIterator(v.into_iter());
     println!("Last element is {}", v.last().unwrap().0);
     //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
     println!("Done");
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
index fe8cf2dcb25..72a6ead47a9 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
@@ -18,7 +18,7 @@ LL |     let _ = DeIterator.last();
    |                        help: try: `next_back()`
 
 error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
-  --> tests/ui/double_ended_iterator_last.rs:96:36
+  --> tests/ui/double_ended_iterator_last.rs:109:36
    |
 LL |     println!("Last element is {}", v.last().unwrap().0);
    |                                    ^^^^^^^^
@@ -26,7 +26,7 @@ LL |     println!("Last element is {}", v.last().unwrap().0);
    = note: this change will alter drop order which may be undesirable
 help: try
    |
-LL ~     let mut v = v.into_iter();
+LL ~     let mut v = DropDeIterator(v.into_iter());
 LL ~     println!("Last element is {}", v.next_back().unwrap().0);
    |
 
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 7c5de8832d6..e9218bbb409 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
@@ -11,6 +11,19 @@ fn main() {
 }
 
 fn drop_order() {
+    struct DropDeIterator(std::vec::IntoIter<S>);
+    impl Iterator for DropDeIterator {
+        type Item = S;
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+    }
+    impl DoubleEndedIterator for DropDeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+
     struct S(&'static str);
     impl std::ops::Drop for S {
         fn drop(&mut self) {
@@ -19,7 +32,7 @@ fn drop_order() {
     }
 
     let v = vec![S("one"), S("two"), S("three")];
-    let v = (v.into_iter(), 42);
+    let v = (DropDeIterator(v.into_iter()), 42);
     println!("Last element is {}", v.0.last().unwrap().0);
     //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
     println!("Done");
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
index 845afc11f04..e330a22a354 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
@@ -1,5 +1,5 @@
 error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
-  --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
+  --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
    |
 LL |     println!("Last element is {}", v.0.last().unwrap().0);
    |                                    ^^^^------
@@ -8,7 +8,7 @@ LL |     println!("Last element is {}", v.0.last().unwrap().0);
    |
    = note: this change will alter drop order which may be undesirable
 note: this must be made mutable to use `.next_back()`
-  --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
+  --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36
    |
 LL |     println!("Last element is {}", v.0.last().unwrap().0);
    |                                    ^^^
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
index f7bbf83654f..18c80c7aba4 100644
--- a/src/tools/clippy/tests/ui/enum_variants.rs
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -220,4 +220,19 @@ mod issue11494 {
     }
 }
 
+mod encapsulated {
+    mod types {
+        pub struct FooError;
+        pub struct BarError;
+        pub struct BazError;
+    }
+
+    enum Error {
+        FooError(types::FooError),
+        BarError(types::BarError),
+        BazError(types::BazError),
+        Other,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed
index 166b1387ba2..ce8b67f9ca7 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.fixed
+++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if matches!(cs.iter().next(), Some('i')) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if matches!(cs.iter().next(), Some(1)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if matches!(get_enum(), Some(MyEnum::B)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs
index 09c2483ae6d..ff09533f265 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.rs
+++ b/src/tools/clippy/tests/ui/equatable_if_let.rs
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if let Some('i') = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if let Some(1) = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if let Some(MyEnum::B) = get_enum() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr
index 81e0e15a5c7..dd1832ad68b 100644
--- a/src/tools/clippy/tests/ui/equatable_if_let.stderr
+++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr
@@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality
 LL |     if let inline!("abc") = "abc" {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
 
-error: aborting due to 14 previous errors
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:109:12
+   |
+LL |         if let Some('i') = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:117:12
+   |
+LL |         if let Some(1) = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:135:12
+   |
+LL |         if let Some(MyEnum::B) = get_enum() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
index e19aa4acb4c..050cdfcba96 100644
--- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed
@@ -1,5 +1,5 @@
 #![deny(clippy::index_refutable_slice)]
-#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
+#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)]
 
 enum SomeEnum<T> {
     One(T),
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
index 29039356855..91429bfea27 100644
--- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::index_refutable_slice)]
-#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
+#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes, clippy::collapsible_if)]
 
 enum SomeEnum<T> {
     One(T),
diff --git a/src/tools/clippy/tests/ui/integer_division.rs b/src/tools/clippy/tests/ui/integer_division.rs
index 632fedc9e8f..a40956e2672 100644
--- a/src/tools/clippy/tests/ui/integer_division.rs
+++ b/src/tools/clippy/tests/ui/integer_division.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::integer_division)]
 
+use std::num::NonZeroU32;
+
+const TWO: NonZeroU32 = NonZeroU32::new(2).unwrap();
+
 fn main() {
     let two = 2;
     let n = 1 / 2;
@@ -12,4 +16,8 @@ fn main() {
     //~^ integer_division
 
     let x = 1. / 2.0;
+
+    let a = 1;
+    let s = a / TWO;
+    //~^ integer_division
 }
diff --git a/src/tools/clippy/tests/ui/integer_division.stderr b/src/tools/clippy/tests/ui/integer_division.stderr
index 0fe2021a1a9..c0e34a562f6 100644
--- a/src/tools/clippy/tests/ui/integer_division.stderr
+++ b/src/tools/clippy/tests/ui/integer_division.stderr
@@ -1,5 +1,5 @@
 error: integer division
-  --> tests/ui/integer_division.rs:5:13
+  --> tests/ui/integer_division.rs:9:13
    |
 LL |     let n = 1 / 2;
    |             ^^^^^
@@ -9,7 +9,7 @@ LL |     let n = 1 / 2;
    = help: to override `-D warnings` add `#[allow(clippy::integer_division)]`
 
 error: integer division
-  --> tests/ui/integer_division.rs:8:13
+  --> tests/ui/integer_division.rs:12:13
    |
 LL |     let o = 1 / two;
    |             ^^^^^^^
@@ -17,12 +17,20 @@ LL |     let o = 1 / two;
    = help: division of integers may cause loss of precision. consider using floats
 
 error: integer division
-  --> tests/ui/integer_division.rs:11:13
+  --> tests/ui/integer_division.rs:15:13
    |
 LL |     let p = two / 4;
    |             ^^^^^^^
    |
    = help: division of integers may cause loss of precision. consider using floats
 
-error: aborting due to 3 previous errors
+error: integer division
+  --> tests/ui/integer_division.rs:21:13
+   |
+LL |     let s = a / TWO;
+   |             ^^^^^^^
+   |
+   = help: division of integers may cause loss of precision. consider using floats
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
index 26ba8682dc2..7f74ab035bd 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
@@ -6,7 +6,6 @@
 extern crate proc_macros;
 use proc_macros::with_span;
 
-use clippy_utils::is_from_proc_macro;
 use std::boxed::Box;
 use std::fmt::Display;
 use std::future::Future;
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
index 86cdd5c662c..54b955ac3a5 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -1,11 +1,11 @@
 error: non-binding `let` without a type annotation
-  --> tests/ui/let_underscore_untyped.rs:51:5
+  --> tests/ui/let_underscore_untyped.rs:50:5
    |
 LL |     let _ = a();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> tests/ui/let_underscore_untyped.rs:51:10
+  --> tests/ui/let_underscore_untyped.rs:50:10
    |
 LL |     let _ = a();
    |          ^
@@ -13,49 +13,49 @@ LL |     let _ = a();
    = help: to override `-D warnings` add `#[allow(clippy::let_underscore_untyped)]`
 
 error: non-binding `let` without a type annotation
-  --> tests/ui/let_underscore_untyped.rs:53:5
+  --> tests/ui/let_underscore_untyped.rs:52:5
    |
 LL |     let _ = b(1);
    |     ^^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> tests/ui/let_underscore_untyped.rs:53:10
+  --> tests/ui/let_underscore_untyped.rs:52:10
    |
 LL |     let _ = b(1);
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> tests/ui/let_underscore_untyped.rs:56:5
+  --> tests/ui/let_underscore_untyped.rs:55:5
    |
 LL |     let _ = d(&1);
    |     ^^^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> tests/ui/let_underscore_untyped.rs:56:10
+  --> tests/ui/let_underscore_untyped.rs:55:10
    |
 LL |     let _ = d(&1);
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> tests/ui/let_underscore_untyped.rs:58:5
+  --> tests/ui/let_underscore_untyped.rs:57:5
    |
 LL |     let _ = e();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> tests/ui/let_underscore_untyped.rs:58:10
+  --> tests/ui/let_underscore_untyped.rs:57:10
    |
 LL |     let _ = e();
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> tests/ui/let_underscore_untyped.rs:60:5
+  --> tests/ui/let_underscore_untyped.rs:59:5
    |
 LL |     let _ = f();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> tests/ui/let_underscore_untyped.rs:60:10
+  --> tests/ui/let_underscore_untyped.rs:59:10
    |
 LL |     let _ = f();
    |          ^
diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.fixed b/src/tools/clippy/tests/ui/let_with_type_underscore.fixed
new file mode 100644
index 00000000000..7a4af4e3d1e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_with_type_underscore.fixed
@@ -0,0 +1,47 @@
+//@aux-build: proc_macros.rs
+#![allow(unused)]
+#![warn(clippy::let_with_type_underscore)]
+#![allow(clippy::let_unit_value, clippy::needless_late_init)]
+
+extern crate proc_macros;
+
+fn func() -> &'static str {
+    ""
+}
+
+#[rustfmt::skip]
+fn main() {
+    // Will lint
+    let x = 1;
+    //~^ let_with_type_underscore
+    let _ = 2;
+    //~^ let_with_type_underscore
+    let x = func();
+    //~^ let_with_type_underscore
+    let x;
+    //~^ let_with_type_underscore
+    x = ();
+
+    let x = 1; // Will not lint, Rust infers this to an integer before Clippy
+    let x = func();
+    let x: Vec<_> = Vec::<u32>::new();
+    let x: [_; 1] = [1];
+    let x = 1;
+    //~^ let_with_type_underscore
+
+    // Do not lint from procedural macros
+    proc_macros::with_span! {
+        span
+        let x: _ = ();
+        // Late initialization
+        let x: _;
+        x = ();
+        // Ensure weird formatting will not break it (hopefully)
+        let x : _ = 1;
+        let x
+: _ = 1;
+        let                   x :              
+        _;
+        x = ();
+    };
+}
diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr
index 2284d1fe2e4..9179f992207 100644
--- a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr
+++ b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr
@@ -4,13 +4,13 @@ error: variable declared with type underscore
 LL |     let x: _ = 1;
    |     ^^^^^^^^^^^^^
    |
-help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:15:10
-   |
-LL |     let x: _ = 1;
-   |          ^^^
    = note: `-D clippy::let-with-type-underscore` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::let_with_type_underscore)]`
+help: remove the explicit type `_` declaration
+   |
+LL -     let x: _ = 1;
+LL +     let x = 1;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:17:5
@@ -19,10 +19,10 @@ LL |     let _: _ = 2;
    |     ^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:17:10
    |
-LL |     let _: _ = 2;
-   |          ^^^
+LL -     let _: _ = 2;
+LL +     let _ = 2;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:19:5
@@ -31,10 +31,10 @@ LL |     let x: _ = func();
    |     ^^^^^^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:19:10
    |
-LL |     let x: _ = func();
-   |          ^^^
+LL -     let x: _ = func();
+LL +     let x = func();
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:21:5
@@ -43,10 +43,10 @@ LL |     let x: _;
    |     ^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:21:10
    |
-LL |     let x: _;
-   |          ^^^
+LL -     let x: _;
+LL +     let x;
+   |
 
 error: variable declared with type underscore
   --> tests/ui/let_with_type_underscore.rs:29:5
@@ -55,10 +55,10 @@ LL |     let x : _ = 1;
    |     ^^^^^^^^^^^^^^
    |
 help: remove the explicit type `_` declaration
-  --> tests/ui/let_with_type_underscore.rs:29:10
    |
-LL |     let x : _ = 1;
-   |          ^^^^
+LL -     let x : _ = 1;
+LL +     let x = 1;
+   |
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
index 57fe8917afe..58ee6978fc1 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
@@ -1,5 +1,21 @@
 #![warn(clippy::manual_div_ceil)]
 
+macro_rules! y {
+    () => {
+        let x = 33u32;
+        let _ = x.div_ceil(8);
+        //~^ manual_div_ceil
+        let _ = x.div_ceil(8);
+        //~^ manual_div_ceil
+    };
+}
+
+macro_rules! eight {
+    () => {
+        8
+    };
+}
+
 fn main() {
     let x = 7_u32;
     let y = 4_u32;
@@ -32,6 +48,13 @@ fn main() {
     let _ = (z as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
+
+    // Test lint with macro
+    y!();
+
+    // Also test if RHS should be result of macro expansion
+    let _ = 33u32.div_ceil(eight!());
+    //~^ manual_div_ceil
 }
 
 fn issue_13843() {
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs
index ec343513e5c..aa0d81b22a0 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs
@@ -1,5 +1,21 @@
 #![warn(clippy::manual_div_ceil)]
 
+macro_rules! y {
+    () => {
+        let x = 33u32;
+        let _ = (x + 7) / 8;
+        //~^ manual_div_ceil
+        let _ = (7 + x) / 8;
+        //~^ manual_div_ceil
+    };
+}
+
+macro_rules! eight {
+    () => {
+        8
+    };
+}
+
 fn main() {
     let x = 7_u32;
     let y = 4_u32;
@@ -32,6 +48,13 @@ fn main() {
     let _ = (z as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
+
+    // Test lint with macro
+    y!();
+
+    // Also test if RHS should be result of macro expansion
+    let _ = (33u32 + 7) / eight!();
+    //~^ manual_div_ceil
 }
 
 fn issue_13843() {
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
index 8e14ab27426..9be5a19bf39 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
@@ -1,5 +1,5 @@
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:9:13
+  --> tests/ui/manual_div_ceil.rs:25:13
    |
 LL |     let _ = (x + (y - 1)) / y;
    |             ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
@@ -8,94 +8,122 @@ LL |     let _ = (x + (y - 1)) / y;
    = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:11:13
+  --> tests/ui/manual_div_ceil.rs:27:13
    |
 LL |     let _ = ((y - 1) + x) / y;
    |             ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:13:13
+  --> tests/ui/manual_div_ceil.rs:29:13
    |
 LL |     let _ = (x + y - 1) / y;
    |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:16:13
+  --> tests/ui/manual_div_ceil.rs:32:13
    |
 LL |     let _ = (7_u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:18:13
+  --> tests/ui/manual_div_ceil.rs:34:13
    |
 LL |     let _ = (7_i32 as u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:39:13
+  --> tests/ui/manual_div_ceil.rs:6:17
+   |
+LL |         let _ = (x + 7) / 8;
+   |                 ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
+...
+LL |     y!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:8:17
+   |
+LL |         let _ = (7 + x) / 8;
+   |                 ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
+...
+LL |     y!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:56:13
+   |
+LL |     let _ = (33u32 + 7) / eight!();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:62:13
    |
 LL |     let _ = (2048 + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:43:13
+  --> tests/ui/manual_div_ceil.rs:66:13
    |
 LL |     let _ = (2048usize + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:47:13
+  --> tests/ui/manual_div_ceil.rs:70:13
    |
 LL |     let _ = (2048_usize + x - 1) / x;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:51:13
+  --> tests/ui/manual_div_ceil.rs:74:13
    |
 LL |     let _ = (x + 4 - 1) / 4;
    |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:54:18
+  --> tests/ui/manual_div_ceil.rs:77:18
    |
 LL |     let _: u32 = (2048 + 6 - 1) / 6;
    |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:56:20
+  --> tests/ui/manual_div_ceil.rs:79:20
    |
 LL |     let _: usize = (2048 + 6 - 1) / 6;
    |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:58:18
+  --> tests/ui/manual_div_ceil.rs:81:18
    |
 LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:61:13
+  --> tests/ui/manual_div_ceil.rs:84:13
    |
 LL |     let _ = (2048 + 6u32 - 1) / 6u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:64:13
+  --> tests/ui/manual_div_ceil.rs:87:13
    |
 LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:70:13
+  --> tests/ui/manual_div_ceil.rs:93:13
    |
 LL |     let _ = (x + 7) / 8;
    |             ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
 
 error: manually reimplementing `div_ceil`
-  --> tests/ui/manual_div_ceil.rs:72:13
+  --> tests/ui/manual_div_ceil.rs:95:13
    |
 LL |     let _ = (7 + x) / 8;
    |             ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
 
-error: aborting due to 16 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index a753566b34c..3781ba1676f 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -514,3 +514,35 @@ mod issue13768 {
         };
     }
 }
+
+mod issue14598 {
+    fn bar() -> Result<bool, &'static str> {
+        let value = match foo() {
+            //~^ manual_let_else
+            Err(_) => return Err("abc"),
+            Ok(value) => value,
+        };
+
+        let w = Some(0);
+        let v = match w {
+            //~^ manual_let_else
+            None => return Err("abc"),
+            Some(x) => x,
+        };
+
+        enum Foo<T> {
+            Foo(T),
+        }
+
+        let v = match Foo::Foo(Some(())) {
+            Foo::Foo(Some(_)) => return Err("abc"),
+            Foo::Foo(v) => v,
+        };
+
+        Ok(value == 42)
+    }
+
+    fn foo() -> Result<u32, &'static str> {
+        todo!()
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr
index ef042192114..a1eea041929 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else.stderr
@@ -529,5 +529,25 @@ LL +                 return;
 LL +             };
    |
 
-error: aborting due to 33 previous errors
+error: this could be rewritten as `let...else`
+  --> tests/ui/manual_let_else.rs:520:9
+   |
+LL | /         let value = match foo() {
+LL | |
+LL | |             Err(_) => return Err("abc"),
+LL | |             Ok(value) => value,
+LL | |         };
+   | |__________^ help: consider writing: `let Ok(value) = foo() else { return Err("abc") };`
+
+error: this could be rewritten as `let...else`
+  --> tests/ui/manual_let_else.rs:527:9
+   |
+LL | /         let v = match w {
+LL | |
+LL | |             None => return Err("abc"),
+LL | |             Some(x) => x,
+LL | |         };
+   | |__________^ help: consider writing: `let Some(v) = w else { return Err("abc") };`
+
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
index 3f73d6e5a1a..304be05f6c4 100644
--- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed
@@ -1,7 +1,5 @@
 #![allow(clippy::legacy_numeric_constants, unused_imports)]
 
-use std::{i32, i128, u32, u128};
-
 fn main() {
     let _ = 1u32.saturating_add(1);
     //~^ manual_saturating_arithmetic
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
index 98246a5cd96..c2b570e974a 100644
--- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs
@@ -1,7 +1,5 @@
 #![allow(clippy::legacy_numeric_constants, unused_imports)]
 
-use std::{i32, i128, u32, u128};
-
 fn main() {
     let _ = 1u32.checked_add(1).unwrap_or(u32::max_value());
     //~^ manual_saturating_arithmetic
diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr
index 9d133d8a073..2f006a3ae17 100644
--- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr
+++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr
@@ -1,5 +1,5 @@
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:6:13
+  --> tests/ui/manual_saturating_arithmetic.rs:4:13
    |
 LL |     let _ = 1u32.checked_add(1).unwrap_or(u32::max_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)`
@@ -8,19 +8,19 @@ LL |     let _ = 1u32.checked_add(1).unwrap_or(u32::max_value());
    = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:8:13
+  --> tests/ui/manual_saturating_arithmetic.rs:6:13
    |
 LL |     let _ = 1u32.checked_add(1).unwrap_or(u32::MAX);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:10:13
+  --> tests/ui/manual_saturating_arithmetic.rs:8:13
    |
 LL |     let _ = 1u8.checked_add(1).unwrap_or(255);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u8.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:12:13
+  --> tests/ui/manual_saturating_arithmetic.rs:10:13
    |
 LL |       let _ = 1u128
    |  _____________^
@@ -30,49 +30,49 @@ LL | |         .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455);
    | |_______________________________________________________________________^ help: consider using `saturating_add`: `1u128.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:18:13
+  --> tests/ui/manual_saturating_arithmetic.rs:16:13
    |
 LL |     let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `1u32.saturating_mul(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:21:13
+  --> tests/ui/manual_saturating_arithmetic.rs:19:13
    |
 LL |     let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:23:13
+  --> tests/ui/manual_saturating_arithmetic.rs:21:13
    |
 LL |     let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:25:13
+  --> tests/ui/manual_saturating_arithmetic.rs:23:13
    |
 LL |     let _ = 1u8.checked_sub(1).unwrap_or(0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u8.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:30:13
+  --> tests/ui/manual_saturating_arithmetic.rs:28:13
    |
 LL |     let _ = 1i32.checked_add(1).unwrap_or(i32::max_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:32:13
+  --> tests/ui/manual_saturating_arithmetic.rs:30:13
    |
 LL |     let _ = 1i32.checked_add(1).unwrap_or(i32::MAX);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:34:13
+  --> tests/ui/manual_saturating_arithmetic.rs:32:13
    |
 LL |     let _ = 1i8.checked_add(1).unwrap_or(127);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:36:13
+  --> tests/ui/manual_saturating_arithmetic.rs:34:13
    |
 LL |       let _ = 1i128
    |  _____________^
@@ -82,25 +82,25 @@ LL | |         .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727);
    | |_______________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:40:13
+  --> tests/ui/manual_saturating_arithmetic.rs:38:13
    |
 LL |     let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:42:13
+  --> tests/ui/manual_saturating_arithmetic.rs:40:13
    |
 LL |     let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:44:13
+  --> tests/ui/manual_saturating_arithmetic.rs:42:13
    |
 LL |     let _ = 1i8.checked_add(-1).unwrap_or(-128);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:46:13
+  --> tests/ui/manual_saturating_arithmetic.rs:44:13
    |
 LL |       let _ = 1i128
    |  _____________^
@@ -110,25 +110,25 @@ LL | |         .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
    | |________________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:54:13
+  --> tests/ui/manual_saturating_arithmetic.rs:52:13
    |
 LL |     let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:56:13
+  --> tests/ui/manual_saturating_arithmetic.rs:54:13
    |
 LL |     let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:58:13
+  --> tests/ui/manual_saturating_arithmetic.rs:56:13
    |
 LL |     let _ = 1i8.checked_sub(1).unwrap_or(-128);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:60:13
+  --> tests/ui/manual_saturating_arithmetic.rs:58:13
    |
 LL |       let _ = 1i128
    |  _____________^
@@ -138,25 +138,25 @@ LL | |         .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728);
    | |________________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:64:13
+  --> tests/ui/manual_saturating_arithmetic.rs:62:13
    |
 LL |     let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:66:13
+  --> tests/ui/manual_saturating_arithmetic.rs:64:13
    |
 LL |     let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:68:13
+  --> tests/ui/manual_saturating_arithmetic.rs:66:13
    |
 LL |     let _ = 1i8.checked_sub(-1).unwrap_or(127);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(-1)`
 
 error: manual saturating arithmetic
-  --> tests/ui/manual_saturating_arithmetic.rs:70:13
+  --> tests/ui/manual_saturating_arithmetic.rs:68:13
    |
 LL |       let _ = 1i128
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.fixed b/src/tools/clippy/tests/ui/manual_slice_fill.fixed
index bba863247f5..d07d1d60e2c 100644
--- a/src/tools/clippy/tests/ui/manual_slice_fill.fixed
+++ b/src/tools/clippy/tests/ui/manual_slice_fill.fixed
@@ -123,3 +123,40 @@ fn issue14189() {
         *b = !*b;
     }
 }
+
+mod issue14685 {
+    use std::ops::{Index, IndexMut};
+
+    #[derive(Clone)]
+    struct ZipList<T>(T);
+
+    impl<T> ZipList<T> {
+        fn len(&self) -> usize {
+            todo!()
+        }
+
+        fn is_empty(&self) -> bool {
+            todo!()
+        }
+    }
+
+    impl<T> Index<usize> for ZipList<T> {
+        type Output = T;
+
+        fn index(&self, _: usize) -> &Self::Output {
+            todo!()
+        }
+    }
+
+    impl<T> IndexMut<usize> for ZipList<T> {
+        fn index_mut(&mut self, _: usize) -> &mut Self::Output {
+            todo!()
+        }
+    }
+
+    fn index_mut(mut zl: ZipList<usize>) {
+        for i in 0..zl.len() {
+            zl[i] = 6;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.rs b/src/tools/clippy/tests/ui/manual_slice_fill.rs
index 44c60dc40f0..c74ab2225c0 100644
--- a/src/tools/clippy/tests/ui/manual_slice_fill.rs
+++ b/src/tools/clippy/tests/ui/manual_slice_fill.rs
@@ -136,3 +136,40 @@ fn issue14189() {
         *b = !*b;
     }
 }
+
+mod issue14685 {
+    use std::ops::{Index, IndexMut};
+
+    #[derive(Clone)]
+    struct ZipList<T>(T);
+
+    impl<T> ZipList<T> {
+        fn len(&self) -> usize {
+            todo!()
+        }
+
+        fn is_empty(&self) -> bool {
+            todo!()
+        }
+    }
+
+    impl<T> Index<usize> for ZipList<T> {
+        type Output = T;
+
+        fn index(&self, _: usize) -> &Self::Output {
+            todo!()
+        }
+    }
+
+    impl<T> IndexMut<usize> for ZipList<T> {
+        fn index_mut(&mut self, _: usize) -> &mut Self::Output {
+            todo!()
+        }
+    }
+
+    fn index_mut(mut zl: ZipList<usize>) {
+        for i in 0..zl.len() {
+            zl[i] = 6;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
index 9dae9fcae07..41ca44ceef4 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -106,3 +106,16 @@ fn issue_12928() {
 fn allowed_manual_unwrap_or_zero() -> u32 {
     Some(42).unwrap_or_default()
 }
+
+mod issue14716 {
+    struct Foo {
+        name: Option<String>,
+    }
+
+    fn bar(project: &Foo) {
+        let _name = match project.name {
+            Some(ref x) => x,
+            None => "",
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
index 539d7a8bbae..343fbc4879c 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -147,3 +147,16 @@ fn allowed_manual_unwrap_or_zero() -> u32 {
         0
     }
 }
+
+mod issue14716 {
+    struct Foo {
+        name: Option<String>,
+    }
+
+    fn bar(project: &Foo) {
+        let _name = match project.name {
+            Some(ref x) => x,
+            None => "",
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed
index 6208ca19b82..c839156bed9 100644
--- a/src/tools/clippy/tests/ui/needless_if.fixed
+++ b/src/tools/clippy/tests/ui/needless_if.fixed
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
 #![allow(
     clippy::blocks_in_conditions,
     clippy::if_same_then_else,
@@ -46,9 +45,7 @@ fn main() {
     if let true = true
         && true
     {}
-    if true
-        && let true = true
-    {}
+    if true && let true = true {}
     // Can lint nested `if let`s
     ({
         //~^ needless_if
diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs
index b459ff877be..11103af5c55 100644
--- a/src/tools/clippy/tests/ui/needless_if.rs
+++ b/src/tools/clippy/tests/ui/needless_if.rs
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
 #![allow(
     clippy::blocks_in_conditions,
     clippy::if_same_then_else,
@@ -46,9 +45,7 @@ fn main() {
     if let true = true
         && true
     {}
-    if true
-        && let true = true
-    {}
+    if true && let true = true {}
     // Can lint nested `if let`s
     if {
         //~^ needless_if
diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr
index eeb8d044526..4b56843bd52 100644
--- a/src/tools/clippy/tests/ui/needless_if.stderr
+++ b/src/tools/clippy/tests/ui/needless_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:27:5
+  --> tests/ui/needless_if.rs:26:5
    |
 LL |     if (true) {}
    |     ^^^^^^^^^^^^ help: you can remove it
@@ -8,13 +8,13 @@ LL |     if (true) {}
    = help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:30:5
+  --> tests/ui/needless_if.rs:29:5
    |
 LL |     if maybe_side_effect() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:36:5
+  --> tests/ui/needless_if.rs:35:5
    |
 LL | /     if {
 LL | |
@@ -31,7 +31,7 @@ LL +     });
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:53:5
+  --> tests/ui/needless_if.rs:50:5
    |
 LL | /     if {
 LL | |
@@ -57,19 +57,19 @@ LL +     } && true);
    |
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:98:5
+  --> tests/ui/needless_if.rs:95:5
    |
 LL |     if { maybe_side_effect() } {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:101:5
+  --> tests/ui/needless_if.rs:98:5
    |
 LL |     if { maybe_side_effect() } && true {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
 
 error: this `if` branch is empty
-  --> tests/ui/needless_if.rs:106:5
+  --> tests/ui/needless_if.rs:103:5
    |
 LL |     if true {}
    |     ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed
index 391d4bc3fcc..b686a8e9f1a 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.fixed
+++ b/src/tools/clippy/tests/ui/needless_late_init.fixed
@@ -1,6 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
-#![allow(unused)]
 #![allow(
     clippy::assign_op_pattern,
     clippy::blocks_in_conditions,
@@ -246,9 +244,7 @@ fn does_not_lint() {
     }
 
     let x;
-    if true
-        && let Some(n) = Some("let chains too")
-    {
+    if true && let Some(n) = Some("let chains too") {
         x = 1;
     } else {
         x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs
index 6096e8300e1..23772ff7029 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.rs
+++ b/src/tools/clippy/tests/ui/needless_late_init.rs
@@ -1,6 +1,4 @@
 //@aux-build:proc_macros.rs
-#![feature(let_chains)]
-#![allow(unused)]
 #![allow(
     clippy::assign_op_pattern,
     clippy::blocks_in_conditions,
@@ -246,9 +244,7 @@ fn does_not_lint() {
     }
 
     let x;
-    if true
-        && let Some(n) = Some("let chains too")
-    {
+    if true && let Some(n) = Some("let chains too") {
         x = 1;
     } else {
         x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index e7c36136847..e3e25cdc8d7 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -1,5 +1,5 @@
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:27:5
+  --> tests/ui/needless_late_init.rs:25:5
    |
 LL |     let a;
    |     ^^^^^^ created here
@@ -17,7 +17,7 @@ LL ~     let a = "zero";
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:31:5
+  --> tests/ui/needless_late_init.rs:29:5
    |
 LL |     let b;
    |     ^^^^^^ created here
@@ -35,7 +35,7 @@ LL ~     let b = 1;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:33:5
+  --> tests/ui/needless_late_init.rs:31:5
    |
 LL |     let c;
    |     ^^^^^^ created here
@@ -52,7 +52,7 @@ LL ~     let c = 2;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:38:5
+  --> tests/ui/needless_late_init.rs:36:5
    |
 LL |     let d: usize;
    |     ^^^^^^^^^^^^^ created here
@@ -68,7 +68,7 @@ LL ~     let d: usize = 1;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:42:5
+  --> tests/ui/needless_late_init.rs:40:5
    |
 LL |     let e;
    |     ^^^^^^ created here
@@ -84,7 +84,7 @@ LL ~     let e = format!("{}", d);
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:48:5
+  --> tests/ui/needless_late_init.rs:46:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -103,7 +103,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:58:5
+  --> tests/ui/needless_late_init.rs:56:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -120,7 +120,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:66:5
+  --> tests/ui/needless_late_init.rs:64:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -138,7 +138,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:75:5
+  --> tests/ui/needless_late_init.rs:73:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -155,7 +155,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:83:5
+  --> tests/ui/needless_late_init.rs:81:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -169,7 +169,7 @@ LL ~         1 => "three",
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:90:5
+  --> tests/ui/needless_late_init.rs:88:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:99:5
+  --> tests/ui/needless_late_init.rs:97:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -203,7 +203,7 @@ LL ~     let x = 1;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:104:5
+  --> tests/ui/needless_late_init.rs:102:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -220,7 +220,7 @@ LL ~     let x = SignificantDrop;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:109:5
+  --> tests/ui/needless_late_init.rs:107:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -238,7 +238,7 @@ LL ~     let x = SignificantDrop;
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:129:5
+  --> tests/ui/needless_late_init.rs:127:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -257,7 +257,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:147:5
+  --> tests/ui/needless_late_init.rs:145:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -276,7 +276,7 @@ LL ~     };
    |
 
 error: unneeded late initialization
-  --> tests/ui/needless_late_init.rs:302:5
+  --> tests/ui/needless_late_init.rs:298:5
    |
 LL |     let r;
    |     ^^^^^^ created here
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index 55da4f28976..8516cee48e6 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -1,100 +1,188 @@
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:20:12
    |
 LL |     return Some(to.magic?);
-   |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |            ^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::needless-question-mark` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]`
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     return Some(to.magic?);
+LL +     return to.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:29:12
    |
 LL |     return Some(to.magic?)
-   |            ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |            ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     return Some(to.magic?)
+LL +     return to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:35:5
    |
 LL |     Some(to.magic?)
-   |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     Some(to.magic?)
+LL +     to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:41:21
    |
 LL |     to.and_then(|t| Some(t.magic?))
-   |                     ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
+   |                     ^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     to.and_then(|t| Some(t.magic?))
+LL +     to.and_then(|t| t.magic)
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:51:9
    |
 LL |         Some(t.magic?)
-   |         ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
+   |         ^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -         Some(t.magic?)
+LL +         t.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:57:12
    |
 LL |     return Ok(tr.magic?);
-   |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |            ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     return Ok(tr.magic?);
+LL +     return tr.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:65:12
    |
 LL |     return Ok(tr.magic?)
-   |            ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |            ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     return Ok(tr.magic?)
+LL +     return tr.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:70:5
    |
 LL |     Ok(tr.magic?)
-   |     ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
+   |     ^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     Ok(tr.magic?)
+LL +     tr.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:75:21
    |
 LL |     tr.and_then(|t| Ok(t.magic?))
-   |                     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |                     ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     tr.and_then(|t| Ok(t.magic?))
+LL +     tr.and_then(|t| t.magic)
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:84:9
    |
 LL |         Ok(t.magic?)
-   |         ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |         ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -         Ok(t.magic?)
+LL +         t.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:92:16
    |
 LL |         return Ok(t.magic?);
-   |                ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
+   |                ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -         return Ok(t.magic?);
+LL +         return t.magic;
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:128:27
    |
 LL |         || -> Option<_> { Some(Some($expr)?) }()
-   |                           ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)`
+   |                           ^^^^^^^^^^^^^^^^^^
 ...
 LL |     let _x = some_and_qmark_in_macro!(x?);
    |              ---------------------------- in this macro invocation
    |
    = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -         || -> Option<_> { Some(Some($expr)?) }()
+LL +         || -> Option<_> { Some($expr) }()
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:140:5
    |
 LL |     Some(to.magic?)
-   |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+   |     ^^^^^^^^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     Some(to.magic?)
+LL +     to.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Ok` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:149:5
    |
 LL |     Ok(s.magic?)
-   |     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
+   |     ^^^^^^^^^^^^
+   |
+help: remove the enclosing `Ok` and `?` operator
+   |
+LL -     Ok(s.magic?)
+LL +     s.magic
+   |
 
-error: question mark operator is useless here
+error: enclosing `Some` and `?` operator are unneeded
   --> tests/ui/needless_question_mark.rs:154:7
    |
 LL |     { Some(a?) }
-   |       ^^^^^^^^ help: try removing question mark and `Some()`: `a`
+   |       ^^^^^^^^
+   |
+help: remove the enclosing `Some` and `?` operator
+   |
+LL -     { Some(a?) }
+LL +     { a }
+   |
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
index 2b30c8f984e..d6c35d8097c 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
@@ -70,3 +70,10 @@ mod external_macros {
     once_cell::external!();
     lazy_static::external!();
 }
+
+mod issue14729 {
+    use once_cell::sync::Lazy;
+
+    #[expect(clippy::non_std_lazy_statics)]
+    static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
+}
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
index c52338eee83..996ef050d69 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
@@ -70,3 +70,10 @@ mod external_macros {
     once_cell::external!();
     lazy_static::external!();
 }
+
+mod issue14729 {
+    use once_cell::sync::Lazy;
+
+    #[expect(clippy::non_std_lazy_statics)]
+    static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
+}
diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed
index 484ff307323..9629b3eea58 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq.fixed
@@ -23,23 +23,25 @@ fn main() {
     //~^ ptr_eq
     let _ = std::ptr::eq(a, b);
     //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_ptr(), b as *const _);
-    //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_ptr(), b.as_ptr());
-    //~^ ptr_eq
 
-    // Do not lint
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_ptr() == b as *const _;
 
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_ptr() == b.as_ptr();
+
+    // Do not lint
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
-    let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
-    //~^ ptr_eq
-    let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
-    //~^ ptr_eq
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_mut_ptr() == b.as_mut_ptr();
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
@@ -51,8 +53,12 @@ fn main() {
     let _ = !std::ptr::eq(x, y);
     //~^ ptr_eq
 
-    #[allow(clippy::eq_op)]
-    let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
+    #[expect(clippy::eq_op)]
+    // Do not lint: casts are needed to not change type
+    let _issue14337 = main as *const () == main as *const ();
+
+    // Do not peel the content of macros
+    let _ = std::ptr::eq(mac!(cast a), mac!(cast b));
     //~^ ptr_eq
 
     // Do not peel the content of macros
diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs
index f28707cc3e9..2b741d8df46 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq.rs
@@ -23,23 +23,25 @@ fn main() {
     //~^ ptr_eq
     let _ = a as *const _ == b as *const _;
     //~^ ptr_eq
+
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_ptr() == b as *const _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_ptr() == b.as_ptr();
-    //~^ ptr_eq
 
     // Do not lint
-
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-    //~^ ptr_eq
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
@@ -51,8 +53,12 @@ fn main() {
     let _ = x as *const u32 != y as *mut u32 as *const u32;
     //~^ ptr_eq
 
-    #[allow(clippy::eq_op)]
+    #[expect(clippy::eq_op)]
+    // Do not lint: casts are needed to not change type
     let _issue14337 = main as *const () == main as *const ();
+
+    // Do not peel the content of macros
+    let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
     //~^ ptr_eq
 
     // Do not peel the content of macros
diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr
index 906831b9e03..e7340624b59 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq.stderr
@@ -14,52 +14,28 @@ LL |     let _ = a as *const _ == b as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:26:13
-   |
-LL |     let _ = a.as_ptr() == b as *const _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:28:13
-   |
-LL |     let _ = a.as_ptr() == b.as_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:39:13
-   |
-LL |     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:41:13
-   |
-LL |     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
-
-error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:48:13
+  --> tests/ui/ptr_eq.rs:50:13
    |
 LL |     let _ = x as *const u32 == y as *mut u32 as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:51:13
+  --> tests/ui/ptr_eq.rs:53:13
    |
 LL |     let _ = x as *const u32 != y as *mut u32 as *const u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:55:23
+  --> tests/ui/ptr_eq.rs:61:13
    |
-LL |     let _issue14337 = main as *const () == main as *const ();
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
+LL |     let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
 
 error: use `std::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq.rs:59:13
+  --> tests/ui/ptr_eq.rs:65:13
    |
 LL |     let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
 
-error: aborting due to 10 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
index d8ee4ea88f8..48cbad62e1a 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
@@ -32,23 +32,25 @@ fn main() {
     //~^ ptr_eq
     let _ = core::ptr::eq(a, b);
     //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_ptr(), b as *const _);
-    //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_ptr(), b.as_ptr());
-    //~^ ptr_eq
 
-    // Do not lint
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_ptr() == b as *const _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_ptr() == b.as_ptr();
 
+    // Do not lint
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
-    let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
-    //~^ ptr_eq
-    let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
-    //~^ ptr_eq
+    // Do not lint: the rhs conversion is needed
+    let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
+
+    // Do not lint: we have two raw pointers already
+    let _ = a.as_mut_ptr() == b.as_mut_ptr();
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
index a236314c29b..3827178640e 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
@@ -32,23 +32,25 @@ fn main() {
     //~^ ptr_eq
     let _ = a as *const _ == b as *const _;
     //~^ ptr_eq
+
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_ptr() == b as *const _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_ptr() == b.as_ptr();
-    //~^ ptr_eq
 
     // Do not lint
-
     let _ = mac!(a, b);
     let _ = another_mac!(a, b);
 
     let a = &mut [1, 2, 3];
     let b = &mut [1, 2, 3];
 
+    // Do not lint: the rhs conversion is needed
     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-    //~^ ptr_eq
+
+    // Do not lint: we have two raw pointers already
     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-    //~^ ptr_eq
 
     let _ = a == b;
     let _ = core::ptr::eq(a, b);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
index 5b8135dc8e8..8c7b1ff7666 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
@@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers
 LL |     let _ = a as *const _ == b as *const _;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)`
 
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:35:13
-   |
-LL |     let _ = a.as_ptr() == b as *const _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:37:13
-   |
-LL |     let _ = a.as_ptr() == b.as_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:48:13
-   |
-LL |     let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
-
-error: use `core::ptr::eq` when comparing raw pointers
-  --> tests/ui/ptr_eq_no_std.rs:50:13
-   |
-LL |     let _ = a.as_mut_ptr() == b.as_mut_ptr();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 6bd071d07f5..507bc2b29d8 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> {
     res
 }
 
+fn expect_expr(a: Option<usize>) -> Option<usize> {
+    #[expect(clippy::needless_question_mark)]
+    Some(a?)
+}
+
 fn main() {}
 
 // `?` is not the same as `return None;` if inside of a try block
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index dd093c9bf48..64b51b849ed 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> {
     res
 }
 
+fn expect_expr(a: Option<usize>) -> Option<usize> {
+    #[expect(clippy::needless_question_mark)]
+    Some(a?)
+}
+
 fn main() {}
 
 // `?` is not the same as `return None;` if inside of a try block
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 8fe04b895ce..d8ce4420aee 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -198,7 +198,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:390:13
+  --> tests/ui/question_mark.rs:395:13
    |
 LL | /             if a.is_none() {
 LL | |
@@ -208,7 +208,7 @@ LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:451:5
+  --> tests/ui/question_mark.rs:456:5
    |
 LL | /     let Some(v) = bar.foo.owned.clone() else {
 LL | |         return None;
@@ -216,7 +216,7 @@ LL | |     };
    | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:466:5
+  --> tests/ui/question_mark.rs:471:5
    |
 LL | /     let Some(ref x) = foo.opt_x else {
 LL | |         return None;
@@ -224,7 +224,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:476:5
+  --> tests/ui/question_mark.rs:481:5
    |
 LL | /     let Some(ref mut x) = foo.opt_x else {
 LL | |         return None;
@@ -232,7 +232,7 @@ LL | |     };
    | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:487:5
+  --> tests/ui/question_mark.rs:492:5
    |
 LL | /     let Some(ref x @ ref y) = foo.opt_x else {
 LL | |         return None;
@@ -240,7 +240,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:491:5
+  --> tests/ui/question_mark.rs:496:5
    |
 LL | /     let Some(ref x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -248,7 +248,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:495:5
+  --> tests/ui/question_mark.rs:500:5
    |
 LL | /     let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
 LL | |         return None;
@@ -256,7 +256,7 @@ LL | |     };
    | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:517:5
+  --> tests/ui/question_mark.rs:522:5
    |
 LL | /     if arg.is_none() {
 LL | |
@@ -265,7 +265,7 @@ LL | |     }
    | |_____^ help: replace it with: `arg?;`
 
 error: this `match` expression can be replaced with `?`
-  --> tests/ui/question_mark.rs:521:15
+  --> tests/ui/question_mark.rs:526:15
    |
 LL |       let val = match arg {
    |  _______________^
@@ -276,7 +276,7 @@ LL | |     };
    | |_____^ help: try instead: `arg?`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:531:5
+  --> tests/ui/question_mark.rs:536:5
    |
 LL | /     let Some(a) = *a else {
 LL | |         return None;
diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr
index 53cb59c0216..82f0d325040 100644
--- a/src/tools/clippy/tests/ui/question_mark_used.stderr
+++ b/src/tools/clippy/tests/ui/question_mark_used.stderr
@@ -1,4 +1,4 @@
-error: question mark operator was used
+error: the `?` operator was used
   --> tests/ui/question_mark_used.rs:11:5
    |
 LL |     other_function()?;
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 33a5308bd35..dc9d6491691 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -1,4 +1,4 @@
-#![feature(let_chains, if_let_guard)]
+#![feature(if_let_guard)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
     clippy::needless_bool,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 60bce2994ea..2e9714ad8e7 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains, if_let_guard)]
+#![feature(if_let_guard)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
     clippy::needless_bool,
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index acf7914d253..55e287b9159 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -63,6 +63,7 @@
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
+#![allow(unnecessary_transmutes)]
 #![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`
@@ -132,5 +133,9 @@
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
 #![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`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 32641a684a4..31dcd2cea08 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -63,6 +63,7 @@
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
+#![allow(unnecessary_transmutes)]
 #![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`
@@ -132,5 +133,9 @@
 #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
 #![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`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index e9d2debff91..a8d5c96acc3 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,412 +8,436 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:72:9
    |
 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`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:73: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:73:9
+  --> tests/ui/rename.rs:74: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:74:9
+  --> tests/ui/rename.rs:75: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:75:9
+  --> tests/ui/rename.rs:76: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:76:9
+  --> tests/ui/rename.rs:77: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:77:9
+  --> 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:78:9
+  --> 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:79:9
+  --> 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`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::fn_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::if_let_redundant_pattern_matching)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:84:9
+  --> 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`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:85:9
+  --> 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`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
-  --> tests/ui/rename.rs:101:9
+  --> 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`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:106: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:106:9
+  --> tests/ui/rename.rs:107: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:107:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::invalid_null_ptr_usage)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
 
 error: lint `clippy::double_neg` has been renamed to `double_negations`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::double_neg)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:118:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:118:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:119:9
+  --> tests/ui/rename.rs:120:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:120:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:121:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:122:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:123:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:124:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::maybe_misused_cfg)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:125:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:126:9
+  --> tests/ui/rename.rs:127:9
    |
 LL | #![warn(clippy::mismatched_target_os)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:127:9
+  --> tests/ui/rename.rs:128:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:128:9
+  --> tests/ui/rename.rs:129:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
-  --> tests/ui/rename.rs:129:9
+  --> tests/ui/rename.rs:130:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:130:9
+  --> tests/ui/rename.rs:131:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:131:9
+  --> tests/ui/rename.rs:132:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:132:9
+  --> tests/ui/rename.rs:133:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:133:9
+  --> tests/ui/rename.rs:134:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
 error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
-  --> tests/ui/rename.rs:134:9
+  --> tests/ui/rename.rs:135:9
    |
 LL | #![warn(clippy::reverse_range_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: aborting due to 69 previous errors
+error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:136:9
+   |
+LL | #![warn(clippy::transmute_int_to_float)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:137:9
+   |
+LL | #![warn(clippy::transmute_int_to_char)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:138:9
+   |
+LL | #![warn(clippy::transmute_float_to_int)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
+  --> tests/ui/rename.rs:139:9
+   |
+LL | #![warn(clippy::transmute_num_to_bytes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+
+error: aborting due to 73 previous errors
 
diff --git a/src/tools/clippy/tests/ui/return_and_then.fixed b/src/tools/clippy/tests/ui/return_and_then.fixed
index 74efa14eeec..8d9481d1595 100644
--- a/src/tools/clippy/tests/ui/return_and_then.fixed
+++ b/src/tools/clippy/tests/ui/return_and_then.fixed
@@ -67,8 +67,60 @@ fn main() {
             .first() // creates temporary reference
             .and_then(|x| test_opt_block(Some(*x)))
     }
+
+    fn in_closure() -> bool {
+        let _ = || {
+            let x = Some("")?;
+            if x.len() > 2 { Some(3) } else { None }
+            //~^ return_and_then
+        };
+        true
+    }
+
+    fn with_return(shortcut: bool) -> Option<i32> {
+        if shortcut {
+            return {
+                let x = Some("")?;
+                if x.len() > 2 { Some(3) } else { None }
+            };
+            //~^ return_and_then
+        };
+        None
+    }
+
+    fn with_return_multiline(shortcut: bool) -> Option<i32> {
+        if shortcut {
+            return {
+                let mut x = Some("")?;
+                let x = format!("{x}.");
+                if x.len() > 2 { Some(3) } else { None }
+            };
+            //~^^^^ return_and_then
+        };
+        None
+    }
 }
 
 fn gen_option(n: i32) -> Option<i32> {
     Some(n)
 }
+
+mod issue14781 {
+    fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> {
+        Ok((1, 1))
+    }
+
+    fn bug(_: Option<&str>) -> Result<(), ()> {
+        let year: Option<&str> = None;
+        let month: Option<&str> = None;
+        let day: Option<&str> = None;
+
+        let _day = if let (Some(year), Some(month)) = (year, month) {
+            day.and_then(|day| foo(day, (1, 31)).ok())
+        } else {
+            None
+        };
+
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/return_and_then.rs b/src/tools/clippy/tests/ui/return_and_then.rs
index 188dc57e588..beada921a91 100644
--- a/src/tools/clippy/tests/ui/return_and_then.rs
+++ b/src/tools/clippy/tests/ui/return_and_then.rs
@@ -63,8 +63,55 @@ fn main() {
             .first() // creates temporary reference
             .and_then(|x| test_opt_block(Some(*x)))
     }
+
+    fn in_closure() -> bool {
+        let _ = || {
+            Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
+            //~^ return_and_then
+        };
+        true
+    }
+
+    fn with_return(shortcut: bool) -> Option<i32> {
+        if shortcut {
+            return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None });
+            //~^ return_and_then
+        };
+        None
+    }
+
+    fn with_return_multiline(shortcut: bool) -> Option<i32> {
+        if shortcut {
+            return Some("").and_then(|mut x| {
+                let x = format!("{x}.");
+                if x.len() > 2 { Some(3) } else { None }
+            });
+            //~^^^^ return_and_then
+        };
+        None
+    }
 }
 
 fn gen_option(n: i32) -> Option<i32> {
     Some(n)
 }
+
+mod issue14781 {
+    fn foo(_: &str, _: (u32, u32)) -> Result<(u32, u32), ()> {
+        Ok((1, 1))
+    }
+
+    fn bug(_: Option<&str>) -> Result<(), ()> {
+        let year: Option<&str> = None;
+        let month: Option<&str> = None;
+        let day: Option<&str> = None;
+
+        let _day = if let (Some(year), Some(month)) = (year, month) {
+            day.and_then(|day| foo(day, (1, 31)).ok())
+        } else {
+            None
+        };
+
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr
index cc611c3dba6..5feca882860 100644
--- a/src/tools/clippy/tests/ui/return_and_then.stderr
+++ b/src/tools/clippy/tests/ui/return_and_then.stderr
@@ -1,4 +1,4 @@
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:5:9
    |
 LL | /         opt.and_then(|n| {
@@ -20,7 +20,7 @@ LL +         ret += n;
 LL +         if n > 1 { Some(ret) } else { None }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:14:9
    |
 LL |         opt.and_then(|n| test_opt_block(Some(n)))
@@ -32,7 +32,7 @@ LL ~         let n = opt?;
 LL +         test_opt_block(Some(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:19:9
    |
 LL |         gen_option(1).and_then(|n| test_opt_block(Some(n)))
@@ -44,7 +44,7 @@ LL ~         let n = gen_option(1)?;
 LL +         test_opt_block(Some(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:24:9
    |
 LL |         opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
@@ -56,7 +56,7 @@ LL ~         let n = opt?;
 LL +         if n > 1 { Ok(n + 1) } else { Err(n) }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:29:9
    |
 LL |         opt.and_then(|n| test_res_block(Ok(n)))
@@ -68,7 +68,7 @@ LL ~         let n = opt?;
 LL +         test_res_block(Ok(n))
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:35:9
    |
 LL |         Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
@@ -80,7 +80,7 @@ LL ~         let x = Some("")?;
 LL +         if x.len() > 2 { Some(3) } else { None }
    |
 
-error: use the question mark operator instead of an `and_then` call
+error: use the `?` operator instead of an `and_then` call
   --> tests/ui/return_and_then.rs:41:9
    |
 LL | /         Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
@@ -101,5 +101,50 @@ LL +         })?;
 LL +         if x.len() > 2 { Some(3) } else { None }
    |
 
-error: aborting due to 7 previous errors
+error: use the `?` operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:69:13
+   |
+LL |             Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~             let x = Some("")?;
+LL +             if x.len() > 2 { Some(3) } else { None }
+   |
+
+error: use the `?` operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:77:20
+   |
+LL |             return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None });
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~             return {
+LL +                 let x = Some("")?;
+LL +                 if x.len() > 2 { Some(3) } else { None }
+LL ~             };
+   |
+
+error: use the `?` operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:85:20
+   |
+LL |               return Some("").and_then(|mut x| {
+   |  ____________________^
+LL | |                 let x = format!("{x}.");
+LL | |                 if x.len() > 2 { Some(3) } else { None }
+LL | |             });
+   | |______________^
+   |
+help: try
+   |
+LL ~             return {
+LL +                 let mut x = Some("")?;
+LL +                 let x = format!("{x}.");
+LL +                 if x.len() > 2 { Some(3) } else { None }
+LL ~             };
+   |
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.fixed b/src/tools/clippy/tests/ui/to_digit_is_some.fixed
index 627d54c5f73..ff6b32e6bd1 100644
--- a/src/tools/clippy/tests/ui/to_digit_is_some.fixed
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.fixed
@@ -9,3 +9,20 @@ fn main() {
     let _ = char::is_digit(c, 8);
     //~^ to_digit_is_some
 }
+
+#[clippy::msrv = "1.86"]
+mod cannot_lint_in_const_context {
+    fn without_const(c: char) -> bool {
+        c.is_digit(8)
+        //~^ to_digit_is_some
+    }
+    const fn with_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+    }
+}
+
+#[clippy::msrv = "1.87"]
+const fn with_const(c: char) -> bool {
+    c.is_digit(8)
+    //~^ to_digit_is_some
+}
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.rs b/src/tools/clippy/tests/ui/to_digit_is_some.rs
index d4eccc9931f..5ba08617433 100644
--- a/src/tools/clippy/tests/ui/to_digit_is_some.rs
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.rs
@@ -9,3 +9,20 @@ fn main() {
     let _ = char::to_digit(c, 8).is_some();
     //~^ to_digit_is_some
 }
+
+#[clippy::msrv = "1.86"]
+mod cannot_lint_in_const_context {
+    fn without_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+        //~^ to_digit_is_some
+    }
+    const fn with_const(c: char) -> bool {
+        c.to_digit(8).is_some()
+    }
+}
+
+#[clippy::msrv = "1.87"]
+const fn with_const(c: char) -> bool {
+    c.to_digit(8).is_some()
+    //~^ to_digit_is_some
+}
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.stderr b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
index f41382a60d5..5ffedb4683f 100644
--- a/src/tools/clippy/tests/ui/to_digit_is_some.stderr
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
@@ -13,5 +13,17 @@ error: use of `.to_digit(..).is_some()`
 LL |     let _ = char::to_digit(c, 8).is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)`
 
-error: aborting due to 2 previous errors
+error: use of `.to_digit(..).is_some()`
+  --> tests/ui/to_digit_is_some.rs:16:9
+   |
+LL |         c.to_digit(8).is_some()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)`
+
+error: use of `.to_digit(..).is_some()`
+  --> tests/ui/to_digit_is_some.rs:26:5
+   |
+LL |     c.to_digit(8).is_some()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_digit(8)`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index 2b8b6c539ad..e968e7a5924 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -116,138 +116,6 @@ fn int_to_bool() {
     //~^ transmute_int_to_bool
 }
 
-#[warn(clippy::transmute_int_to_float)]
-mod int_to_float {
-    fn test() {
-        let _: f16 = unsafe { std::mem::transmute(0_u16) };
-        //~^ transmute_int_to_float
-
-        let _: f16 = unsafe { std::mem::transmute(0_i16) };
-        //~^ transmute_int_to_float
-
-        let _: f32 = unsafe { std::mem::transmute(0_u32) };
-        //~^ transmute_int_to_float
-
-        let _: f32 = unsafe { std::mem::transmute(0_i32) };
-        //~^ transmute_int_to_float
-
-        let _: f64 = unsafe { std::mem::transmute(0_u64) };
-        //~^ transmute_int_to_float
-
-        let _: f64 = unsafe { std::mem::transmute(0_i64) };
-        //~^ transmute_int_to_float
-
-        let _: f128 = unsafe { std::mem::transmute(0_u128) };
-        //~^ transmute_int_to_float
-
-        let _: f128 = unsafe { std::mem::transmute(0_i128) };
-        //~^ transmute_int_to_float
-    }
-
-    mod issue_5747 {
-        const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
-        //~^ transmute_int_to_float
-
-        const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
-        //~^ transmute_int_to_float
-
-        const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
-        //~^ transmute_int_to_float
-
-        const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
-        //~^ transmute_int_to_float
-
-        const fn from_bits_16(v: i16) -> f16 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_32(v: i32) -> f32 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_64(v: u64) -> f64 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-
-        const fn from_bits_128(v: u128) -> f128 {
-            unsafe { std::mem::transmute(v) }
-            //~^ transmute_int_to_float
-        }
-    }
-}
-
-mod num_to_bytes {
-    fn test() {
-        unsafe {
-            let _: [u8; 1] = std::mem::transmute(0u8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0u32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0u128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 1] = std::mem::transmute(0i8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0i32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0i128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 2] = std::mem::transmute(0.0f16);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0.0f32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 8] = std::mem::transmute(0.0f64);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0.0f128);
-            //~^ transmute_num_to_bytes
-        }
-    }
-    const fn test_const() {
-        unsafe {
-            let _: [u8; 1] = std::mem::transmute(0u8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0u32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0u128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 1] = std::mem::transmute(0i8);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0i32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0i128);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 2] = std::mem::transmute(0.0f16);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 4] = std::mem::transmute(0.0f32);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 8] = std::mem::transmute(0.0f64);
-            //~^ transmute_num_to_bytes
-
-            let _: [u8; 16] = std::mem::transmute(0.0f128);
-            //~^ transmute_num_to_bytes
-        }
-    }
-}
-
 fn bytes_to_str(mb: &mut [u8]) {
     const B: &[u8] = b"";
 
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index 1bb70151965..79528ec06f1 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -97,230 +97,8 @@ LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
 
-error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:122:31
-   |
-LL |         let _: f16 = unsafe { std::mem::transmute(0_u16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
-   |
-   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
-
-error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:125:31
-   |
-LL |         let _: f16 = unsafe { std::mem::transmute(0_i16) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)`
-
-error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:128:31
-   |
-LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
-
-error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:131:31
-   |
-LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
-
-error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:134:31
-   |
-LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
-
-error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:137:31
-   |
-LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
-
-error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:140:32
-   |
-LL |         let _: f128 = unsafe { std::mem::transmute(0_u128) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)`
-
-error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:143:32
-   |
-LL |         let _: f128 = unsafe { std::mem::transmute(0_i128) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
-
-error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:148:39
-   |
-LL |         const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
-
-error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:151:39
-   |
-LL |         const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
-
-error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:154:39
-   |
-LL |         const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
-
-error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:157:41
-   |
-LL |         const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
-
-error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:161:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
-
-error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:166:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
-
-error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:171:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
-
-error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:176:22
-   |
-LL |             unsafe { std::mem::transmute(v) }
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
-
-error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:185:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0u8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
-   |
-   = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
-
-error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:188:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0u32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
-
-error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:191:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0u128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
-
-error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:194:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0i8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
-
-error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:197:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0i32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
-
-error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:200:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0i128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
-
-error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:203:30
-   |
-LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
-
-error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:206:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
-
-error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:209:30
-   |
-LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
-
-error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:212:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
-
-error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:218:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0u8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
-
-error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:221:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0u32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
-
-error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:224:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0u128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
-
-error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:227:30
-   |
-LL |             let _: [u8; 1] = std::mem::transmute(0i8);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
-
-error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:230:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0i32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
-
-error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:233:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0i128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
-
-error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:236:30
-   |
-LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
-
-error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:239:30
-   |
-LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
-
-error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:242:30
-   |
-LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
-
-error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:245:31
-   |
-LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
-
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:254:28
+  --> tests/ui/transmute.rs:122:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -329,16 +107,16 @@ LL |     let _: &str = unsafe { std::mem::transmute(B) };
    = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> tests/ui/transmute.rs:257:32
+  --> tests/ui/transmute.rs:125:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:260:30
+  --> tests/ui/transmute.rs:128:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
 
-error: aborting due to 54 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
deleted file mode 100644
index 844445907d7..00000000000
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
+++ /dev/null
@@ -1,60 +0,0 @@
-#![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-#![feature(f128)]
-#![feature(f16)]
-
-fn float_to_int() {
-    let _: u32 = unsafe { 1f32.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: i32 = unsafe { 1f32.to_bits() as i32 };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { 1f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: i64 = unsafe { 1f64.to_bits() as i64 };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { 1.0f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { (-1.0f64).to_bits() };
-    //~^ transmute_float_to_int
-}
-
-mod issue_5747 {
-    const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 };
-    //~^ transmute_float_to_int
-
-    const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 };
-    //~^ transmute_float_to_int
-
-    const VALUE64: u64 = unsafe { 1f64.to_bits() };
-    //~^ transmute_float_to_int
-
-    const VALUE128: u128 = unsafe { 1f128.to_bits() };
-    //~^ transmute_float_to_int
-
-    const fn to_bits_16(v: f16) -> u16 {
-        unsafe { v.to_bits() }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_32(v: f32) -> u32 {
-        unsafe { v.to_bits() }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_64(v: f64) -> i64 {
-        unsafe { v.to_bits() as i64 }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_128(v: f128) -> i128 {
-        unsafe { v.to_bits() as i128 }
-        //~^ transmute_float_to_int
-    }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
deleted file mode 100644
index a1f3b15bbfe..00000000000
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-#![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-#![feature(f128)]
-#![feature(f16)]
-
-fn float_to_int() {
-    let _: u32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    let _: i32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    let _: i64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(1.0) };
-    //~^ transmute_float_to_int
-
-    let _: u64 = unsafe { std::mem::transmute(-1.0) };
-    //~^ transmute_float_to_int
-}
-
-mod issue_5747 {
-    const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
-    //~^ transmute_float_to_int
-
-    const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
-    //~^ transmute_float_to_int
-
-    const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
-    //~^ transmute_float_to_int
-
-    const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
-    //~^ transmute_float_to_int
-
-    const fn to_bits_16(v: f16) -> u16 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_32(v: f32) -> u32 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_64(v: f64) -> i64 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-
-    const fn to_bits_128(v: f128) -> i128 {
-        unsafe { std::mem::transmute(v) }
-        //~^ transmute_float_to_int
-    }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
deleted file mode 100644
index 223cbc4e90c..00000000000
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:7:27
-   |
-LL |     let _: u32 = unsafe { std::mem::transmute(1f32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()`
-   |
-   = note: `-D clippy::transmute-float-to-int` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]`
-
-error: transmute from a `f32` to a `i32`
-  --> tests/ui/transmute_float_to_int.rs:10:27
-   |
-LL |     let _: i32 = unsafe { std::mem::transmute(1f32) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:13:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(1f64) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
-
-error: transmute from a `f64` to a `i64`
-  --> tests/ui/transmute_float_to_int.rs:16:27
-   |
-LL |     let _: i64 = unsafe { std::mem::transmute(1f64) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:19:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(1.0) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:22:27
-   |
-LL |     let _: u64 = unsafe { std::mem::transmute(-1.0) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
-
-error: transmute from a `f16` to a `i16`
-  --> tests/ui/transmute_float_to_int.rs:27:35
-   |
-LL |     const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16`
-
-error: transmute from a `f32` to a `i32`
-  --> tests/ui/transmute_float_to_int.rs:30:35
-   |
-LL |     const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
-
-error: transmute from a `f64` to a `u64`
-  --> tests/ui/transmute_float_to_int.rs:33:35
-   |
-LL |     const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
-
-error: transmute from a `f128` to a `u128`
-  --> tests/ui/transmute_float_to_int.rs:36:37
-   |
-LL |     const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()`
-
-error: transmute from a `f16` to a `u16`
-  --> tests/ui/transmute_float_to_int.rs:40:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
-
-error: transmute from a `f32` to a `u32`
-  --> tests/ui/transmute_float_to_int.rs:45:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
-
-error: transmute from a `f64` to a `i64`
-  --> tests/ui/transmute_float_to_int.rs:50:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64`
-
-error: transmute from a `f128` to a `i128`
-  --> tests/ui/transmute_float_to_int.rs:55:18
-   |
-LL |         unsafe { std::mem::transmute(v) }
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128`
-
-error: aborting due to 14 previous errors
-
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
deleted file mode 100644
index 28644aa9ebb..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
+++ /dev/null
@@ -1,16 +0,0 @@
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-fn int_to_char() {
-    let _: char = unsafe { std::char::from_u32(0_u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { std::mem::transmute(0_u32) };
-    const _: char = unsafe { std::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs
deleted file mode 100644
index 8c83ecc8914..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-fn int_to_char() {
-    let _: char = unsafe { std::mem::transmute(0_u32) };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { std::mem::transmute(0_i32) };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { std::mem::transmute(0_u32) };
-    const _: char = unsafe { std::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr
deleted file mode 100644
index e3a3620f28b..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:5:28
-   |
-LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
-   |
-   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
-
-error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char.rs:8:28
-   |
-LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
deleted file mode 100644
index e6e09a2be4b..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
+++ /dev/null
@@ -1,28 +0,0 @@
-#![no_std]
-#![feature(lang_items)]
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-use core::panic::PanicInfo;
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
-
-fn int_to_char() {
-    let _: char = unsafe { core::char::from_u32(0_u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { core::mem::transmute(0_u32) };
-    const _: char = unsafe { core::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
deleted file mode 100644
index 0f2106df00e..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-#![no_std]
-#![feature(lang_items)]
-#![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
-
-use core::panic::PanicInfo;
-
-#[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
-
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
-    loop {}
-}
-
-fn int_to_char() {
-    let _: char = unsafe { core::mem::transmute(0_u32) };
-    //~^ transmute_int_to_char
-
-    let _: char = unsafe { core::mem::transmute(0_i32) };
-    //~^ transmute_int_to_char
-
-    // These shouldn't warn
-    const _: char = unsafe { core::mem::transmute(0_u32) };
-    const _: char = unsafe { core::mem::transmute(0_i32) };
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr
deleted file mode 100644
index d94580a84d7..00000000000
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: transmute from a `u32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:17:28
-   |
-LL |     let _: char = unsafe { core::mem::transmute(0_u32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()`
-   |
-   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]`
-
-error: transmute from a `i32` to a `char`
-  --> tests/ui/transmute_int_to_char_no_std.rs:20:28
-   |
-LL |     let _: char = unsafe { core::mem::transmute(0_i32) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
index d325887bfba..e75678d5fd9 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
@@ -12,7 +12,7 @@ pub fn foo<T>(_t: T)
 where
     T: Copy,
     T: Clone,
-    //~^ ERROR: this type has already been used as a bound predicate
+    //~^ type_repetition_in_bounds
 {
     unimplemented!();
 }
@@ -30,7 +30,7 @@ trait LintBounds
 where
     Self: Clone,
     Self: Copy + Default + Ord,
-    //~^ ERROR: this type has already been used as a bound predicate
+    //~^ type_repetition_in_bounds
     Self: Add<Output = Self> + AddAssign + Sub<Output = Self> + SubAssign,
     Self: Mul<Output = Self> + MulAssign + Div<Output = Self> + DivAssign,
 {
@@ -105,13 +105,13 @@ where
 pub fn f<T: ?Sized>()
 where
     T: Clone,
-    //~^ ERROR: this type has already been used as a bound predicate
+    //~^ type_repetition_in_bounds
 {
 }
 pub fn g<T: Clone>()
 where
     T: ?Sized,
-    //~^ ERROR: this type has already been used as a bound predicate
+    //~^ type_repetition_in_bounds
 {
 }
 
@@ -137,10 +137,27 @@ mod issue8772_pass {
     pub fn f<T: ?Sized, U>(arg: usize)
     where
         T: Trait<Option<usize>, Box<[String]>, bool> + 'static,
-        //~^ ERROR: this type has already been used as a bound predicate
+        //~^ type_repetition_in_bounds
         U: Clone + Sync + 'static,
     {
     }
 }
 
+struct Issue14744<'a, K: 'a>
+where
+    K: Clone,
+{
+    phantom: std::marker::PhantomData<&'a K>,
+}
+//~^^^^ type_repetition_in_bounds
+
+struct ComplexType<T>
+where
+    Vec<T>: Clone,
+    Vec<T>: Clone,
+{
+    t: T,
+}
+//~^^^^ type_repetition_in_bounds
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
index 77944c95045..de1b14da198 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
@@ -1,4 +1,4 @@
-error: this type has already been used as a bound predicate
+error: type `T` has already been used as a bound predicate
   --> tests/ui/type_repetition_in_bounds.rs:14:5
    |
 LL |     T: Clone,
@@ -11,7 +11,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::type_repetition_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this type has already been used as a bound predicate
+error: type `Self` has already been used as a bound predicate
   --> tests/ui/type_repetition_in_bounds.rs:32:5
    |
 LL |     Self: Copy + Default + Ord,
@@ -19,7 +19,7 @@ LL |     Self: Copy + Default + Ord,
    |
    = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
 
-error: this type has already been used as a bound predicate
+error: type `T` has already been used as a bound predicate
   --> tests/ui/type_repetition_in_bounds.rs:107:5
    |
 LL |     T: Clone,
@@ -27,7 +27,7 @@ LL |     T: Clone,
    |
    = help: consider combining the bounds: `T: ?Sized + Clone`
 
-error: this type has already been used as a bound predicate
+error: type `T` has already been used as a bound predicate
   --> tests/ui/type_repetition_in_bounds.rs:113:5
    |
 LL |     T: ?Sized,
@@ -35,13 +35,29 @@ LL |     T: ?Sized,
    |
    = help: consider combining the bounds: `T: Clone + ?Sized`
 
-error: this type has already been used as a bound predicate
+error: type `T` has already been used as a bound predicate
   --> tests/ui/type_repetition_in_bounds.rs:139:9
    |
 LL |         T: Trait<Option<usize>, Box<[String]>, bool> + 'static,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider combining the bounds: `T: ?Sized + Trait<Option<usize>, Box<[String]>, bool>`
+   = help: consider combining the bounds: `T: ?Sized + Trait<Option<usize>, Box<[String]>, bool> + 'static`
 
-error: aborting due to 5 previous errors
+error: type `K` has already been used as a bound predicate
+  --> tests/ui/type_repetition_in_bounds.rs:148:5
+   |
+LL |     K: Clone,
+   |     ^^^^^^^^
+   |
+   = help: consider combining the bounds: `K: 'a + Clone`
+
+error: type `Vec<T>` has already been used as a bound predicate
+  --> tests/ui/type_repetition_in_bounds.rs:157:5
+   |
+LL |     Vec<T>: Clone,
+   |     ^^^^^^^^^^^^^
+   |
+   = help: consider combining the bounds: `Vec<T>: Clone + Clone`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index ba167e79a30..91ff4b9ee77 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -266,7 +266,21 @@ mod fixable {
     // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
     // `*x.pow(2)` which tries to dereference the return value rather than `x`.
     fn issue_11968(x: &usize) -> usize {
-        { *x }.pow(2)
+        (*x).pow(2)
+        //~^ unnecessary_cast
+    }
+
+    #[allow(clippy::cast_lossless)]
+    fn issue_14640() {
+        let x = 5usize;
+        let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
+        assert_eq!(vec.len(), x);
+        //~^ unnecessary_cast
+
+        let _ = (5i32 as i64).abs();
+        //~^ unnecessary_cast
+
+        let _ = 5i32 as i64;
         //~^ unnecessary_cast
     }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index 0f90a8b0596..5444a914db1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -269,4 +269,18 @@ mod fixable {
         (*x as usize).pow(2)
         //~^ unnecessary_cast
     }
+
+    #[allow(clippy::cast_lossless)]
+    fn issue_14640() {
+        let x = 5usize;
+        let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
+        assert_eq!(vec.len(), x as usize);
+        //~^ unnecessary_cast
+
+        let _ = (5i32 as i64 as i64).abs();
+        //~^ unnecessary_cast
+
+        let _ = 5i32 as i64 as i64;
+        //~^ unnecessary_cast
+    }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index c83770c1a29..3e3c5eb81c1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`)
   --> tests/ui/unnecessary_cast.rs:269:9
    |
 LL |         (*x as usize).pow(2)
-   |         ^^^^^^^^^^^^^ help: try: `{ *x }`
+   |         ^^^^^^^^^^^^^ help: try: `(*x)`
 
-error: aborting due to 41 previous errors
+error: casting to the same type is unnecessary (`usize` -> `usize`)
+  --> tests/ui/unnecessary_cast.rs:277:31
+   |
+LL |         assert_eq!(vec.len(), x as usize);
+   |                               ^^^^^^^^^^ help: try: `x`
+
+error: casting to the same type is unnecessary (`i64` -> `i64`)
+  --> tests/ui/unnecessary_cast.rs:280:17
+   |
+LL |         let _ = (5i32 as i64 as i64).abs();
+   |                 ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
+
+error: casting to the same type is unnecessary (`i64` -> `i64`)
+  --> tests/ui/unnecessary_cast.rs:283:17
+   |
+LL |         let _ = 5i32 as i64 as i64;
+   |                 ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
+
+error: aborting due to 44 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 5aaf7b9f5b5..433459253dd 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -119,3 +119,11 @@ fn main() {
     foo();
     bar();
 }
+
+mod issue14704 {
+    use std::sync::Arc;
+
+    trait Action {
+        async fn cancel(self: Arc<Self>) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
new file mode 100644
index 00000000000..93dd58b8e9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
@@ -0,0 +1,146 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![feature(closure_lifetime_binder)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+#![allow(clippy::from_over_into)]
+
+struct Unitter;
+impl Unitter {
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn(), G>(&self, f: F, _g: G)
+    //~^ unused_unit
+    //~| unused_unit
+    where G: Fn() {
+    //~^ unused_unit
+        let _y: &dyn Fn() = &f;
+        //~^ unused_unit
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) {
+    //~^ unused_unit
+        
+        //~^ unused_unit
+    }
+}
+
+trait Trait {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn();
+        //~^ unused_unit
+}
+
+impl Trait for Unitter {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn() {}
+        //~^ unused_unit
+}
+
+fn return_unit() {  }
+//~^ unused_unit
+//~| unused_unit
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+        //~^ unused_unit
+    }
+    return;
+    //~^ unused_unit
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
+
+#[rustfmt::skip]
+fn test(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test2(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test3(){}
+//~^ unused_unit
+
+fn macro_expr() {
+    macro_rules! e {
+        () => (());
+    }
+    e!()
+}
+
+mod issue9748 {
+    fn main() {
+        let _ = for<'a> |_: &'a u32| -> () {};
+    }
+}
+
+mod issue9949 {
+    fn main() {
+        #[doc = "documentation"]
+        ()
+    }
+}
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
new file mode 100644
index 00000000000..13cc20d4d7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr
@@ -0,0 +1,128 @@
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:37:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+   |
+note: the lint level is defined here
+  --> tests/ui/unused_unit.rs:15:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:62:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:28
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:25:18
+   |
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:27:26
+   |
+LL |         let _y: &dyn Fn() -> () = &f;
+   |                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:35:18
+   |
+LL |     fn into(self) -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:43:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:46:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:48:16
+   |
+LL |         H: Fn() -> ();
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:53:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:56:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:58:16
+   |
+LL |         H: Fn() -> () {}
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:62:17
+   |
+LL | fn return_unit() -> () { () }
+   |                 ^^^^^^ help: remove the `-> ()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:74:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:77:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:95:10
+   |
+LL | fn test()->(){}
+   |          ^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:99:11
+   |
+LL | fn test2() ->(){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:103:11
+   |
+LL | fn test3()-> (){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:136:15
+   |
+LL |         run(|| -> () { todo!() }); 
+   |               ^^^^^^ help: remove the `-> ()`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
new file mode 100644
index 00000000000..987d901b97d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
@@ -0,0 +1,146 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![feature(closure_lifetime_binder)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+#![allow(dead_code)]
+#![allow(clippy::from_over_into)]
+
+struct Unitter;
+impl Unitter {
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn(), G>(&self, f: F, _g: G)
+    //~^ unused_unit
+    //~| unused_unit
+    where G: Fn() {
+    //~^ unused_unit
+        let _y: &dyn Fn() = &f;
+        //~^ unused_unit
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) {
+    //~^ unused_unit
+        
+        //~^ unused_unit
+    }
+}
+
+trait Trait {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn();
+        //~^ unused_unit
+}
+
+impl Trait for Unitter {
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
+    //~^ unused_unit
+    where
+        G: FnMut(),
+        //~^ unused_unit
+        H: Fn() {}
+        //~^ unused_unit
+}
+
+fn return_unit() {  }
+//~^ unused_unit
+//~| unused_unit
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+#[allow(clippy::unit_cmp)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+        //~^ unused_unit
+    }
+    return;
+    //~^ unused_unit
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/4076
+fn foo() {
+    macro_rules! foo {
+        (recv($r:expr) -> $res:pat => $body:expr) => {
+            $body
+        }
+    }
+
+    foo! {
+        recv(rx) -> _x => ()
+    }
+}
+
+#[rustfmt::skip]
+fn test(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test2(){}
+//~^ unused_unit
+
+#[rustfmt::skip]
+fn test3(){}
+//~^ unused_unit
+
+fn macro_expr() {
+    macro_rules! e {
+        () => (());
+    }
+    e!()
+}
+
+mod issue9748 {
+    fn main() {
+        let _ = for<'a> |_: &'a u32| -> () {};
+    }
+}
+
+mod issue9949 {
+    fn main() {
+        #[doc = "documentation"]
+        ()
+    }
+}
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| -> () { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr
new file mode 100644
index 00000000000..a79e70e066b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr
@@ -0,0 +1,122 @@
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:37:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+   |
+note: the lint level is defined here
+  --> tests/ui/unused_unit.rs:15:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:62:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:28
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:25:18
+   |
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:22:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:27:26
+   |
+LL |         let _y: &dyn Fn() -> () = &f;
+   |                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:35:18
+   |
+LL |     fn into(self) -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:43:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:46:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:48:16
+   |
+LL |         H: Fn() -> ();
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:53:29
+   |
+LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
+   |                             ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:56:19
+   |
+LL |         G: FnMut() -> (),
+   |                   ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:58:16
+   |
+LL |         H: Fn() -> () {}
+   |                ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:62:17
+   |
+LL | fn return_unit() -> () { () }
+   |                 ^^^^^^ help: remove the `-> ()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:74:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> tests/ui/unused_unit.rs:77:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:95:10
+   |
+LL | fn test()->(){}
+   |          ^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:99:11
+   |
+LL | fn test2() ->(){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:103:11
+   |
+LL | fn test3()-> (){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: aborting due to 19 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed
index e3c02681c9f..6668bf90c09 100644
--- a/src/tools/clippy/tests/ui/unused_unit.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.fixed
@@ -120,3 +120,24 @@ mod issue9949 {
         ()
     }
 }
+
+#[clippy::msrv = "1.85"]
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    fn bar() {
+        run(|| -> () { todo!() });
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
index 4353026c594..b7645f7b6a2 100644
--- a/src/tools/clippy/tests/ui/unused_unit.rs
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -1,4 +1,6 @@
-
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
 
 // The output for humans should just highlight the whole span without showing
 // the suggested replacement, but we also want to test that suggested
@@ -120,3 +122,25 @@ mod issue9949 {
         ()
     }
 }
+
+mod issue14577 {
+    trait Unit {}
+    impl Unit for () {}
+
+    fn run<R: Unit>(f: impl FnOnce() -> R) {
+        f();
+    }
+
+    #[allow(dependency_on_unit_never_type_fallback)]
+    fn bar() {
+        run(|| -> () { todo!() }); 
+        //~[edition2021]^ unused_unit
+    }
+
+    struct UnitStruct;
+    impl UnitStruct {
+        fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
+            todo!()
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr
index 172fe065502..366f2142095 100644
--- a/src/tools/clippy/tests/ui/unused_unit.stderr
+++ b/src/tools/clippy/tests/ui/unused_unit.stderr
@@ -1,8 +1,8 @@
-error: unneeded unit return type
-  --> tests/ui/unused_unit.rs:20:58
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:35:9
    |
-LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                                                          ^^^^^^ help: remove the `-> ()`
+LL |         ()
+   |         ^^ help: remove the final `()`
    |
 note: the lint level is defined here
   --> tests/ui/unused_unit.rs:13:9
@@ -10,6 +10,12 @@ note: the lint level is defined here
 LL | #![deny(clippy::unused_unit)]
    |         ^^^^^^^^^^^^^^^^^^^
 
+error: unneeded unit expression
+  --> tests/ui/unused_unit.rs:60:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
 error: unneeded unit return type
   --> tests/ui/unused_unit.rs:20:28
    |
@@ -23,6 +29,12 @@ LL |     where G: Fn() -> () {
    |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
+  --> tests/ui/unused_unit.rs:20:58
+   |
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                                                          ^^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
   --> tests/ui/unused_unit.rs:25:26
    |
 LL |         let _y: &dyn Fn() -> () = &f;
@@ -34,12 +46,6 @@ error: unneeded unit return type
 LL |     fn into(self) -> () {
    |                  ^^^^^^ help: remove the `-> ()`
 
-error: unneeded unit expression
-  --> tests/ui/unused_unit.rs:35:9
-   |
-LL |         ()
-   |         ^^ help: remove the final `()`
-
 error: unneeded unit return type
   --> tests/ui/unused_unit.rs:41:29
    |
@@ -82,12 +88,6 @@ error: unneeded unit return type
 LL | fn return_unit() -> () { () }
    |                 ^^^^^^ help: remove the `-> ()`
 
-error: unneeded unit expression
-  --> tests/ui/unused_unit.rs:60:26
-   |
-LL | fn return_unit() -> () { () }
-   |                          ^^ help: remove the final `()`
-
 error: unneeded `()`
   --> tests/ui/unused_unit.rs:72:14
    |
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
index d0bb571273b..b429f3a8a0b 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -66,3 +66,20 @@ fn main() {
         SOME.expect("Still not three?");
     }
 }
+
+mod with_expansion {
+    macro_rules! open {
+        ($file:expr) => {
+            std::fs::File::open($file)
+        };
+    }
+
+    fn test(file: &str) {
+        use std::io::Read;
+        let mut s = String::new();
+        let _ = open!(file).unwrap(); //~ unwrap_used
+        let _ = open!(file).expect("can open"); //~ expect_used
+        let _ = open!(file).unwrap_err(); //~ unwrap_used
+        let _ = open!(file).expect_err("can open"); //~ expect_used
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
index 79eac3f58cc..6fd1b84d812 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
@@ -50,5 +50,37 @@ LL |     a.expect_err("Hello error!");
    |
    = note: if this value is an `Ok`, it will panic
 
-error: aborting due to 6 previous errors
+error: used `unwrap()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:80:17
+   |
+LL |         let _ = open!(file).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Err`, it will panic
+
+error: used `expect()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:81:17
+   |
+LL |         let _ = open!(file).expect("can open");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Err`, it will panic
+
+error: used `unwrap_err()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:82:17
+   |
+LL |         let _ = open!(file).unwrap_err();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Ok`, it will panic
+
+error: used `expect_err()` on a `Result` value
+  --> tests/ui/unwrap_expect_used.rs:83:17
+   |
+LL |         let _ = open!(file).expect_err("can open");
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is an `Ok`, it will panic
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index a26b4a34190..17510683f03 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -16,7 +16,7 @@ use crate::fn_mod::foo;
 //~^ wildcard_imports
 use crate::mod_mod::inner_mod;
 //~^ wildcard_imports
-use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod};
 //~^ wildcard_imports
 #[macro_use]
 use crate::struct_mod::{A, inner_struct_mod};
@@ -26,7 +26,7 @@ use crate::struct_mod::{A, inner_struct_mod};
 use wildcard_imports_helper::inner::inner_for_self_import;
 use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 //~^ wildcard_imports
-use wildcard_imports_helper::{ExternA, extern_foo};
+use wildcard_imports_helper::{extern_foo, ExternA};
 //~^ wildcard_imports
 
 use std::io::prelude::*;
@@ -138,7 +138,7 @@ mod in_fn_test {
     fn test_extern() {
         use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
         //~^ wildcard_imports
-        use wildcard_imports_helper::{ExternA, extern_foo};
+        use wildcard_imports_helper::{extern_foo, ExternA};
         //~^ wildcard_imports
 
         inner_for_self_import::inner_extern_foo();
@@ -160,7 +160,7 @@ mod in_fn_test {
     }
 
     fn test_extern_reexported() {
-        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+        use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum};
         //~^ wildcard_imports
 
         extern_exported();
@@ -190,7 +190,7 @@ mod in_fn_test {
 }
 
 fn test_reexported() {
-    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+    use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum};
     //~^ wildcard_imports
 
     exported();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index f774126102b..26434656a50 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -17,7 +17,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:19:5
    |
 LL | use crate::multi_fn_mod::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:22:5
@@ -35,7 +35,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:29:5
    |
 LL | use wildcard_imports_helper::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:100:13
@@ -59,7 +59,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:141:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:154:20
@@ -77,13 +77,13 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:163:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:193:9
    |
 LL |     use crate::in_fn_test::*;
-   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports.rs:203:9
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
index a3d1aebba8a..f97b883ea23 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -14,7 +14,7 @@ use crate::fn_mod::foo;
 //~^ wildcard_imports
 use crate::mod_mod::inner_mod;
 //~^ wildcard_imports
-use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod};
 //~^ wildcard_imports
 use crate::struct_mod::{A, inner_struct_mod};
 //~^ wildcard_imports
@@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod};
 use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 //~^ wildcard_imports
 use wildcard_imports_helper::prelude::v1::*;
-use wildcard_imports_helper::{ExternA, extern_foo};
+use wildcard_imports_helper::{extern_foo, ExternA};
 //~^ wildcard_imports
 
 use std::io::prelude::*;
@@ -132,7 +132,7 @@ mod in_fn_test {
     fn test_extern() {
         use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
         //~^ wildcard_imports
-        use wildcard_imports_helper::{ExternA, extern_foo};
+        use wildcard_imports_helper::{extern_foo, ExternA};
         //~^ wildcard_imports
 
         inner_for_self_import::inner_extern_foo();
@@ -154,7 +154,7 @@ mod in_fn_test {
     }
 
     fn test_extern_reexported() {
-        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+        use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum};
         //~^ wildcard_imports
 
         extern_exported();
@@ -184,7 +184,7 @@ mod in_fn_test {
 }
 
 fn test_reexported() {
-    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+    use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum};
     //~^ wildcard_imports
 
     exported();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
index a1b557f39f0..873ce41b04f 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -17,7 +17,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:17:5
    |
 LL | use crate::multi_fn_mod::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:19:5
@@ -35,7 +35,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:26:5
    |
 LL | use wildcard_imports_helper::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:95:13
@@ -59,7 +59,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:135:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:148:20
@@ -77,13 +77,13 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:157:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:187:9
    |
 LL |     use crate::in_fn_test::*;
-   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:197:9
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
index a3d1aebba8a..f97b883ea23 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -14,7 +14,7 @@ use crate::fn_mod::foo;
 //~^ wildcard_imports
 use crate::mod_mod::inner_mod;
 //~^ wildcard_imports
-use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod};
 //~^ wildcard_imports
 use crate::struct_mod::{A, inner_struct_mod};
 //~^ wildcard_imports
@@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod};
 use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 //~^ wildcard_imports
 use wildcard_imports_helper::prelude::v1::*;
-use wildcard_imports_helper::{ExternA, extern_foo};
+use wildcard_imports_helper::{extern_foo, ExternA};
 //~^ wildcard_imports
 
 use std::io::prelude::*;
@@ -132,7 +132,7 @@ mod in_fn_test {
     fn test_extern() {
         use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
         //~^ wildcard_imports
-        use wildcard_imports_helper::{ExternA, extern_foo};
+        use wildcard_imports_helper::{extern_foo, ExternA};
         //~^ wildcard_imports
 
         inner_for_self_import::inner_extern_foo();
@@ -154,7 +154,7 @@ mod in_fn_test {
     }
 
     fn test_extern_reexported() {
-        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+        use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum};
         //~^ wildcard_imports
 
         extern_exported();
@@ -184,7 +184,7 @@ mod in_fn_test {
 }
 
 fn test_reexported() {
-    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+    use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum};
     //~^ wildcard_imports
 
     exported();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
index a1b557f39f0..873ce41b04f 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -17,7 +17,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:17:5
    |
 LL | use crate::multi_fn_mod::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:19:5
@@ -35,7 +35,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:26:5
    |
 LL | use wildcard_imports_helper::*;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:95:13
@@ -59,7 +59,7 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:135:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:148:20
@@ -77,13 +77,13 @@ error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:157:13
    |
 LL |         use wildcard_imports_helper::*;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:187:9
    |
 LL |     use crate::in_fn_test::*;
-   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}`
 
 error: usage of wildcard import
   --> tests/ui/wildcard_imports_2021.rs:197:9
diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs
index 25bbc02ffb7..395f9dd2def 100644
--- a/src/tools/clippy/tests/ui/zombie_processes.rs
+++ b/src/tools/clippy/tests/ui/zombie_processes.rs
@@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus {
     let mut x = Command::new("").spawn().unwrap();
     return x.wait().unwrap();
 }
+
+mod issue14677 {
+    use std::io;
+    use std::process::Command;
+
+    fn do_something<F: Fn() -> Result<(), ()>>(f: F) {
+        todo!()
+    }
+
+    fn foo() {
+        let mut child = Command::new("true").spawn().unwrap();
+        let some_condition = true;
+        do_something(|| {
+            if some_condition {
+                return Err(());
+            }
+            Ok(())
+        });
+        child.kill().unwrap();
+        child.wait().unwrap();
+    }
+}
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index f27b109e995..eb2f9f9dd61 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -13,7 +13,9 @@ allow-unauthenticated = [
 
 [note]
 
-[canonicalize-issue-links]
+[close]
+
+[issue-links]
 
 # Prevents mentions in commits to avoid users being spammed
 [no-mentions]
@@ -42,7 +44,7 @@ new_pr = true
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
 users_on_vacation = [
     "matthiaskrgr",
-    "samueltardieu",
+    "Manishearth",
 ]
 
 [assign.owners]
diff --git a/src/tools/clippy/util/etc/pre-commit.sh b/src/tools/clippy/util/etc/pre-commit.sh
index 5dd2ba3d5f5..528f8953b25 100755
--- a/src/tools/clippy/util/etc/pre-commit.sh
+++ b/src/tools/clippy/util/etc/pre-commit.sh
@@ -6,7 +6,6 @@ set -e
 # Update lints
 cargo dev update_lints
 git add clippy_lints/src/lib.rs
-git add clippy_lints/src/lib.*.rs
 
 # Formatting:
 #     Git will not automatically add the formatted code to the staged changes once
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 93f7b1cb7cf..3b544d8b828 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -37,7 +37,7 @@ libc = "0.2"
 miow = "0.6"
 
 [target.'cfg(windows)'.dependencies.windows]
-version = "0.59.0"
+version = "0.61.0"
 features = [
     "Win32_Foundation",
     "Win32_System_Diagnostics_Debug",
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 1449e9af19a..5757e422ae2 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -35,6 +35,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-32bit",
     "ignore-64bit",
     "ignore-aarch64",
+    "ignore-aarch64-pc-windows-msvc",
     "ignore-aarch64-unknown-linux-gnu",
     "ignore-aix",
     "ignore-android",
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index a45f39b036c..b5a2b7feac9 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -15,6 +15,7 @@ pub enum ErrorKind {
     Note,
     Suggestion,
     Warning,
+    Raw,
 }
 
 impl ErrorKind {
@@ -39,6 +40,7 @@ impl ErrorKind {
             "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
             "SUGGESTION" => ErrorKind::Suggestion,
             "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
+            "RAW" => ErrorKind::Raw,
             _ => panic!(
                 "unexpected diagnostic kind `{s}`, expected \
                  `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
@@ -55,6 +57,7 @@ impl fmt::Display for ErrorKind {
             ErrorKind::Note => write!(f, "NOTE"),
             ErrorKind::Suggestion => write!(f, "SUGGESTION"),
             ErrorKind::Warning => write!(f, "WARN"),
+            ErrorKind::Raw => write!(f, "RAW"),
         }
     }
 }
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 960f5ba5888..6ed2b52c66d 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -7,7 +7,6 @@ use regex::Regex;
 use serde::Deserialize;
 
 use crate::errors::{Error, ErrorKind};
-use crate::runtest::ProcRes;
 
 #[derive(Deserialize)]
 struct Diagnostic {
@@ -140,28 +139,19 @@ pub fn extract_rendered(output: &str) -> String {
         .collect()
 }
 
-pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
+pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
     let mut errors = Vec::new();
     for line in output.lines() {
-        // The compiler sometimes intermingles non-JSON stuff into the
-        // output.  This hack just skips over such lines. Yuck.
-        if line.starts_with('{') {
-            match serde_json::from_str::<Diagnostic>(line) {
-                Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
-                Err(error) => {
-                    // Ignore the future compat report message - this is handled
-                    // by `extract_rendered`
-                    if serde_json::from_str::<FutureIncompatReport>(line).is_err() {
-                        proc_res.fatal(
-                        Some(&format!(
-                            "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
-                            error, line, output
-                        )),
-                        || (),
-                    );
-                    }
-                }
-            }
+        // Compiler can emit non-json lines in non-`--error-format=json` modes,
+        // and in some situations even in json mode.
+        match serde_json::from_str::<Diagnostic>(line) {
+            Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
+            Err(_) => errors.push(Error {
+                line_num: None,
+                kind: ErrorKind::Raw,
+                msg: line.to_string(),
+                require_annotation: false,
+            }),
         }
     }
     errors
@@ -181,8 +171,6 @@ fn push_actual_errors(
         .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
         .collect();
 
-    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();
-
     let primary_spans: Vec<_> = spans_info_in_this_file
         .iter()
         .filter(|(is_primary, _)| *is_primary)
@@ -280,7 +268,9 @@ fn push_actual_errors(
                     line_num: Some(span.line_start + index),
                     kind: ErrorKind::Suggestion,
                     msg: line.to_string(),
-                    require_annotation: true,
+                    // Empty suggestions (suggestions to remove something) are common
+                    // and annotating them in source is not useful.
+                    require_annotation: !line.is_empty(),
                 });
             }
         }
@@ -294,13 +284,16 @@ fn push_actual_errors(
     }
 
     // Add notes for any labels that appear in the message.
-    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
-        errors.push(Error {
-            line_num: Some(span.line_start),
-            kind: ErrorKind::Note,
-            msg: span.label.clone().unwrap(),
-            require_annotation: true,
-        });
+    for (_, span) in spans_info_in_this_file {
+        if let Some(label) = &span.label {
+            errors.push(Error {
+                line_num: Some(span.line_start),
+                kind: ErrorKind::Note,
+                msg: label.clone(),
+                // Empty labels (only underlining spans) are common and do not need annotations.
+                require_annotation: !label.is_empty(),
+            });
+        }
     }
 
     // Flatten out the children.
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 97cb82c9e36..75f24adb70f 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -23,7 +23,7 @@ use crate::common::{
     output_base_dir, output_base_name, output_testname_unique,
 };
 use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
-use crate::errors::{Error, ErrorKind};
+use crate::errors::{Error, ErrorKind, load_errors};
 use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
 use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
@@ -577,23 +577,9 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn check_all_error_patterns(
-        &self,
-        output_to_check: &str,
-        proc_res: &ProcRes,
-        pm: Option<PassMode>,
-    ) {
-        if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() {
-            if pm.is_some() {
-                // FIXME(#65865)
-                return;
-            } else {
-                self.fatal(&format!("no error pattern specified in {}", self.testpaths.file));
-            }
-        }
-
+    /// Check `error-pattern` and `regex-error-pattern` directives.
+    fn check_all_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) {
         let mut missing_patterns: Vec<String> = Vec::new();
-
         self.check_error_patterns(output_to_check, &mut missing_patterns);
         self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns);
 
@@ -670,7 +656,9 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn check_expected_errors(&self, expected_errors: Vec<Error>, proc_res: &ProcRes) {
+    /// Check `//~ KIND message` annotations.
+    fn check_expected_errors(&self, proc_res: &ProcRes) {
+        let expected_errors = load_errors(&self.testpaths.file, self.revision);
         debug!(
             "check_expected_errors: expected_errors={:?} proc_res.status={:?}",
             expected_errors, proc_res.status
@@ -711,11 +699,24 @@ impl<'test> TestCx<'test> {
             .collect();
 
         // Parse the JSON output from the compiler and extract out the messages.
-        let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
+        let actual_errors = json::parse_output(&diagnostic_file_name, &self.get_output(proc_res))
+            .into_iter()
+            .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e });
+
         let mut unexpected = Vec::new();
         let mut found = vec![false; expected_errors.len()];
-        for mut actual_error in actual_errors {
-            actual_error.msg = self.normalize_output(&actual_error.msg, &[]);
+        for actual_error in actual_errors {
+            for pattern in &self.props.error_patterns {
+                let pattern = pattern.trim();
+                if actual_error.msg.contains(pattern) {
+                    let q = if actual_error.line_num.is_none() { "?" } else { "" };
+                    self.fatal(&format!(
+                        "error pattern '{pattern}' is found in structured \
+                         diagnostics, use `//~{q} {} {pattern}` instead",
+                        actual_error.kind,
+                    ));
+                }
+            }
 
             let opt_index =
                 expected_errors.iter().enumerate().position(|(index, expected_error)| {
@@ -1582,7 +1583,10 @@ impl<'test> TestCx<'test> {
             Crashes => {
                 set_mir_dump_dir(&mut rustc);
             }
-            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | RustdocJs => {
+            CodegenUnits => {
+                rustc.arg("-Zprint-mono-items");
+            }
+            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | RustdocJs => {
                 // do not use JSON output
             }
         }
@@ -2605,18 +2609,19 @@ impl<'test> TestCx<'test> {
             (expected, actual)
         };
 
-        // Write the actual output to a file in build/
-        let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
+        // Write the actual output to a file in build directory.
         let actual_path = self
             .output_base_name()
             .with_extra_extension(self.revision.unwrap_or(""))
-            .with_extra_extension(test_name)
+            .with_extra_extension(
+                self.config.compare_mode.as_ref().map(|cm| cm.to_str()).unwrap_or(""),
+            )
             .with_extra_extension(stream);
 
         if let Err(err) = fs::write(&actual_path, &actual) {
-            self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
+            self.fatal(&format!("failed to write {stream} to `{actual_path}`: {err}",));
         }
-        println!("Saved the actual {stream} to {actual_path:?}");
+        println!("Saved the actual {stream} to `{actual_path}`");
 
         if !self.config.bless {
             if expected.is_empty() {
@@ -2642,13 +2647,16 @@ impl<'test> TestCx<'test> {
 
             if !actual.is_empty() {
                 if let Err(err) = fs::write(&expected_path, &actual) {
-                    self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
+                    self.fatal(&format!("failed to write {stream} to `{expected_path}`: {err}"));
                 }
-                println!("Blessing the {stream} of {test_name} in {expected_path:?}");
+                println!(
+                    "Blessing the {stream} of `{test_name}` as `{expected_path}`",
+                    test_name = self.testpaths.file
+                );
             }
         }
 
-        println!("\nThe actual {0} differed from the expected {0}.", stream);
+        println!("\nThe actual {stream} differed from the expected {stream}");
 
         if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed }
     }
diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs
index ea985866a05..90cff6bab4d 100644
--- a/src/tools/compiletest/src/runtest/incremental.rs
+++ b/src/tools/compiletest/src/runtest/incremental.rs
@@ -100,16 +100,8 @@ impl TestCx<'_> {
         self.check_no_compiler_crash(&proc_res, self.props.should_ice);
 
         let output_to_check = self.get_output(&proc_res);
-        let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
-        if !expected_errors.is_empty() {
-            if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
-            {
-                self.fatal("both error pattern and expected errors specified");
-            }
-            self.check_expected_errors(expected_errors, &proc_res);
-        } else {
-            self.check_all_error_patterns(&output_to_check, &proc_res, pm);
-        }
+        self.check_expected_errors(&proc_res);
+        self.check_all_error_patterns(&output_to_check, &proc_res);
         if self.props.should_ice {
             match proc_res.status.code() {
                 Some(101) => (),
@@ -137,6 +129,6 @@ impl TestCx<'_> {
 
         let output_to_check = self.get_output(&proc_res);
         self.check_correct_failure_status(&proc_res);
-        self.check_all_error_patterns(&output_to_check, &proc_res, pm);
+        self.check_all_error_patterns(&output_to_check, &proc_res);
     }
 }
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index cf0ae14f81b..cc50a918f75 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -9,7 +9,7 @@ use super::{
     AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
     Truncated, UI_FIXED, WillExecute,
 };
-use crate::{errors, json};
+use crate::json;
 
 impl TestCx<'_> {
     pub(super) fn run_ui_test(&self) {
@@ -127,9 +127,7 @@ impl TestCx<'_> {
             );
         }
 
-        let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
-
-        if let WillExecute::Yes = should_run {
+        let output_to_check = if let WillExecute::Yes = should_run {
             let proc_res = self.exec_compiled_test();
             let run_output_errors = if self.props.check_run_results {
                 self.load_compare_outputs(&proc_res, TestOutput::Run, explicit)
@@ -150,44 +148,19 @@ impl TestCx<'_> {
                 self.fatal_proc_rec("test run succeeded!", &proc_res);
             }
 
-            let output_to_check = self.get_output(&proc_res);
-            if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
-            {
-                // "// error-pattern" comments
-                self.check_all_error_patterns(&output_to_check, &proc_res, pm);
-            }
-            self.check_forbid_output(&output_to_check, &proc_res)
-        }
+            self.get_output(&proc_res)
+        } else {
+            self.get_output(&proc_res)
+        };
 
         debug!(
-            "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \
+            "run_ui_test: explicit={:?} config.compare_mode={:?} \
                proc_res.status={:?} props.error_patterns={:?}",
-            explicit,
-            self.config.compare_mode,
-            expected_errors,
-            proc_res.status,
-            self.props.error_patterns
+            explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns
         );
 
-        if !explicit && self.config.compare_mode.is_none() {
-            // "//~ERROR comments"
-            self.check_expected_errors(expected_errors, &proc_res);
-        } else if explicit && !expected_errors.is_empty() {
-            let msg = format!(
-                "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead",
-                expected_errors[0].line_num_str(),
-                expected_errors[0].kind,
-            );
-            self.fatal(&msg);
-        }
-        let output_to_check = self.get_output(&proc_res);
-        if should_run == WillExecute::No
-            && (!self.props.error_patterns.is_empty()
-                || !self.props.regex_error_patterns.is_empty())
-        {
-            // "// error-pattern" comments
-            self.check_all_error_patterns(&output_to_check, &proc_res, pm);
-        }
+        self.check_expected_errors(&proc_res);
+        self.check_all_error_patterns(&output_to_check, &proc_res);
         self.check_forbid_output(&output_to_check, &proc_res);
 
         if self.props.run_rustfix && self.config.compare_mode.is_none() {
diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml
index 7f14286b5d0..36a66f16030 100644
--- a/src/tools/coverage-dump/Cargo.toml
+++ b/src/tools/coverage-dump/Cargo.toml
@@ -7,8 +7,9 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.71"
+itertools = "0.12"
 leb128 = "0.2.5"
 md5 = { package = "md-5" , version = "0.10.5" }
-miniz_oxide = "0.7.1"
+miniz_oxide = "0.8.8"
 regex = "1.8.4"
 rustc-demangle = "0.1.23"
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs
index 82ebd33d0d1..1cc9f4dc5d6 100644
--- a/src/tools/coverage-dump/src/covfun.rs
+++ b/src/tools/coverage-dump/src/covfun.rs
@@ -1,23 +1,33 @@
 use std::collections::HashMap;
 use std::fmt::{self, Debug, Write as _};
-use std::sync::OnceLock;
+use std::sync::LazyLock;
 
-use anyhow::{Context, anyhow};
+use anyhow::{Context, anyhow, bail, ensure};
+use itertools::Itertools;
 use regex::Regex;
 
-use crate::parser::{Parser, unescape_llvm_string_contents};
+use crate::covmap::FilenameTables;
+use crate::llvm_utils::unescape_llvm_string_contents;
+use crate::parser::Parser;
+
+#[cfg(test)]
+mod tests;
 
 pub(crate) fn dump_covfun_mappings(
     llvm_ir: &str,
+    filename_tables: &FilenameTables,
     function_names: &HashMap<u64, String>,
 ) -> anyhow::Result<()> {
     // Extract function coverage entries from the LLVM IR assembly, and associate
     // each entry with its (demangled) name.
     let mut covfun_entries = llvm_ir
         .lines()
-        .filter_map(covfun_line_data)
-        .map(|line_data| (function_names.get(&line_data.name_hash).map(String::as_str), line_data))
-        .collect::<Vec<_>>();
+        .filter(|line| is_covfun_line(line))
+        .map(parse_covfun_line)
+        .map_ok(|line_data| {
+            (function_names.get(&line_data.name_hash).map(String::as_str), line_data)
+        })
+        .collect::<Result<Vec<_>, _>>()?;
     covfun_entries.sort_by(|a, b| {
         // Sort entries primarily by name, to help make the order consistent
         // across platforms and relatively insensitive to changes.
@@ -41,8 +51,12 @@ pub(crate) fn dump_covfun_mappings(
         println!("Number of files: {num_files}");
 
         for i in 0..num_files {
-            let global_file_id = parser.read_uleb128_u32()?;
-            println!("- file {i} => global file {global_file_id}");
+            let global_file_id = parser.read_uleb128_usize()?;
+            let &CovfunLineData { filenames_hash, .. } = line_data;
+            let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else {
+                bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}");
+            };
+            println!("- file {i} => {filename}");
         }
 
         let num_expressions = parser.read_uleb128_u32()?;
@@ -107,36 +121,50 @@ pub(crate) fn dump_covfun_mappings(
     Ok(())
 }
 
+#[derive(Debug, PartialEq, Eq)]
 struct CovfunLineData {
-    name_hash: u64,
     is_used: bool,
+    name_hash: u64,
+    filenames_hash: u64,
     payload: Vec<u8>,
 }
 
-/// Checks a line of LLVM IR assembly to see if it contains an `__llvm_covfun`
-/// entry, and if so extracts relevant data in a `CovfunLineData`.
-fn covfun_line_data(line: &str) -> Option<CovfunLineData> {
-    let re = {
-        // We cheat a little bit and match variable names `@__covrec_[HASH]u`
-        // rather than the section name, because the section name is harder to
-        // extract and differs across Linux/Windows/macOS. We also extract the
-        // symbol name hash from the variable name rather than the data, since
-        // it's easier and both should match.
-        static RE: OnceLock<Regex> = OnceLock::new();
-        RE.get_or_init(|| {
-            Regex::new(
-                r#"^@__covrec_(?<name_hash>[0-9A-Z]+)(?<is_used>u)? = .*\[[0-9]+ x i8\] c"(?<payload>[^"]*)".*$"#,
-            )
-            .unwrap()
-        })
-    };
+fn is_covfun_line(line: &str) -> bool {
+    line.starts_with("@__covrec_")
+}
 
-    let captures = re.captures(line)?;
-    let name_hash = u64::from_str_radix(&captures["name_hash"], 16).unwrap();
+/// Given a line of LLVM IR assembly that should contain an `__llvm_covfun`
+/// entry, parses it to extract relevant data in a `CovfunLineData`.
+fn parse_covfun_line(line: &str) -> anyhow::Result<CovfunLineData> {
+    ensure!(is_covfun_line(line));
+
+    // We cheat a little bit and match variable names `@__covrec_[HASH]u`
+    // rather than the section name, because the section name is harder to
+    // extract and differs across Linux/Windows/macOS.
+    const RE_STRING: &str = r#"(?x)^
+        @__covrec_[0-9A-Z]+(?<is_used>u)?
+        \ = \ # (trailing space)
+        .*
+        <\{
+            \ i64 \ (?<name_hash> -? [0-9]+),
+            \ i32 \ -? [0-9]+, # (length of payload; currently unused)
+            \ i64 \ -? [0-9]+, # (source hash; currently unused)
+            \ i64 \ (?<filenames_hash> -? [0-9]+),
+            \ \[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
+            \ # (trailing space)
+        }>
+        .*$
+    "#;
+    static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
+
+    let captures =
+        RE.captures(line).with_context(|| format!("couldn't parse covfun line: {line:?}"))?;
     let is_used = captures.name("is_used").is_some();
+    let name_hash = i64::from_str_radix(&captures["name_hash"], 10).unwrap() as u64;
+    let filenames_hash = i64::from_str_radix(&captures["filenames_hash"], 10).unwrap() as u64;
     let payload = unescape_llvm_string_contents(&captures["payload"]);
 
-    Some(CovfunLineData { name_hash, is_used, payload })
+    Ok(CovfunLineData { is_used, name_hash, filenames_hash, payload })
 }
 
 // Extra parser methods only needed when parsing `covfun` payloads.
diff --git a/src/tools/coverage-dump/src/covfun/tests.rs b/src/tools/coverage-dump/src/covfun/tests.rs
new file mode 100644
index 00000000000..1ce833784bd
--- /dev/null
+++ b/src/tools/coverage-dump/src/covfun/tests.rs
@@ -0,0 +1,53 @@
+use super::{CovfunLineData, parse_covfun_line};
+
+/// Integers in LLVM IR are not inherently signed/unsigned, and the text format tends
+/// to emit them in signed form, so this helper function converts `i64` to `u64`.
+fn as_u64(x: i64) -> u64 {
+    x as u64
+}
+
+#[test]
+fn parse_covfun_line_data() {
+    struct Case {
+        line: &'static str,
+        expected: CovfunLineData,
+    }
+    let cases = &[
+        // Copied from `trivial.ll`:
+        Case {
+            line: r#"@__covrec_49A9BAAE5F896E81u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 5307978893922758273, i32 9, i64 445092354169400020, i64 6343436898695299756, [9 x i8] c"\01\01\00\01\01\03\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
+            expected: CovfunLineData {
+                is_used: true,
+                name_hash: as_u64(5307978893922758273),
+                filenames_hash: as_u64(6343436898695299756),
+                payload: b"\x01\x01\x00\x01\x01\x03\x01\x00\x0D".to_vec(),
+            },
+        },
+        // Copied from `on-off-sandwich.ll`:
+        Case {
+            line: r#"@__covrec_D0CE53C5E64F319Au = linkonce_odr hidden constant <{ i64, i32, i64, i64, [14 x i8] }> <{ i64 -3400688559180533350, i32 14, i64 7307957714577672185, i64 892196767019953100, [14 x i8] c"\01\01\00\02\01\10\05\02\10\01\07\05\00\06" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
+            expected: CovfunLineData {
+                is_used: true,
+                name_hash: as_u64(-3400688559180533350),
+                filenames_hash: as_u64(892196767019953100),
+                payload: b"\x01\x01\x00\x02\x01\x10\x05\x02\x10\x01\x07\x05\x00\x06".to_vec(),
+            },
+        },
+        // Copied from `no-core.ll`:
+        Case {
+            line: r#"@__covrec_F8016FC82D46106u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 1116917981370409222, i32 9, i64 -8857254680411629915, i64 -3625186110715410276, [9 x i8] c"\01\01\00\01\01\0C\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#,
+            expected: CovfunLineData {
+                is_used: true,
+                name_hash: as_u64(1116917981370409222),
+                filenames_hash: as_u64(-3625186110715410276),
+                payload: b"\x01\x01\x00\x01\x01\x0C\x01\x00\x0D".to_vec(),
+            },
+        },
+    ];
+
+    for &Case { line, ref expected } in cases {
+        println!("- {line}");
+        let line_data = parse_covfun_line(line).map_err(|e| e.to_string());
+        assert_eq!(line_data.as_ref(), Ok(expected));
+    }
+}
diff --git a/src/tools/coverage-dump/src/covmap.rs b/src/tools/coverage-dump/src/covmap.rs
new file mode 100644
index 00000000000..2246ca2d575
--- /dev/null
+++ b/src/tools/coverage-dump/src/covmap.rs
@@ -0,0 +1,75 @@
+use std::collections::HashMap;
+use std::sync::LazyLock;
+
+use anyhow::{Context, ensure};
+use regex::Regex;
+
+use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents};
+use crate::parser::Parser;
+
+#[derive(Debug, Default)]
+pub(crate) struct FilenameTables {
+    map: HashMap<u64, Vec<String>>,
+}
+
+impl FilenameTables {
+    pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> {
+        let table = self.map.get(&filenames_hash)?;
+        let filename = table.get(global_file_id)?;
+        Some(filename)
+    }
+}
+
+struct CovmapLineData {
+    payload: Vec<u8>,
+}
+
+pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result<FilenameTables> {
+    let mut map = HashMap::default();
+
+    for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) {
+        let CovmapLineData { payload } = parse_covmap_line(line)?;
+
+        let mut parser = Parser::new(&payload);
+        let n_filenames = parser.read_uleb128_usize()?;
+        let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
+        parser.ensure_empty()?;
+
+        let mut filenames_table = vec![];
+
+        let mut parser = Parser::new(&uncompressed_bytes);
+        for _ in 0..n_filenames {
+            let len = parser.read_uleb128_usize()?;
+            let bytes = parser.read_n_bytes(len)?;
+            let filename = str::from_utf8(bytes)?;
+            filenames_table.push(filename.to_owned());
+        }
+
+        let filenames_hash = truncated_md5(&payload);
+        map.insert(filenames_hash, filenames_table);
+    }
+
+    Ok(FilenameTables { map })
+}
+
+fn is_covmap_line(line: &str) -> bool {
+    line.starts_with("@__llvm_coverage_mapping ")
+}
+
+fn parse_covmap_line(line: &str) -> anyhow::Result<CovmapLineData> {
+    ensure!(is_covmap_line(line));
+
+    const RE_STRING: &str = r#"(?x)^
+        @__llvm_coverage_mapping \ =
+        .*
+        \[ [0-9]+ \ x \ i8 \] \ c"(?<payload>[^"]*)"
+        .*$
+    "#;
+    static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(RE_STRING).unwrap());
+
+    let captures =
+        RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?;
+    let payload = unescape_llvm_string_contents(&captures["payload"]);
+
+    Ok(CovmapLineData { payload })
+}
diff --git a/src/tools/coverage-dump/src/llvm_utils.rs b/src/tools/coverage-dump/src/llvm_utils.rs
new file mode 100644
index 00000000000..92322b256a8
--- /dev/null
+++ b/src/tools/coverage-dump/src/llvm_utils.rs
@@ -0,0 +1,85 @@
+use std::borrow::Cow;
+use std::sync::OnceLock;
+
+use anyhow::{anyhow, ensure};
+use regex::bytes;
+
+use crate::parser::Parser;
+
+#[cfg(test)]
+mod tests;
+
+/// Given the raw contents of a string literal in LLVM IR assembly, decodes any
+/// backslash escapes and returns a vector containing the resulting byte string.
+pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec<u8> {
+    let escape_re = {
+        static RE: OnceLock<bytes::Regex> = OnceLock::new();
+        // LLVM IR supports two string escapes: `\\` and `\xx`.
+        RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap())
+    };
+
+    fn u8_from_hex_digits(digits: &[u8]) -> u8 {
+        // We know that the input contains exactly 2 hex digits, so these calls
+        // should never fail.
+        assert_eq!(digits.len(), 2);
+        let digits = std::str::from_utf8(digits).unwrap();
+        u8::from_str_radix(digits, 16).unwrap()
+    }
+
+    escape_re
+        .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| {
+            let byte = match captures.get(1) {
+                None => b'\\',
+                Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()),
+            };
+            [byte]
+        })
+        .into_owned()
+}
+
+/// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to
+/// 64 bits as a way to associate data stored in different tables/sections.
+pub(crate) fn truncated_md5(bytes: &[u8]) -> u64 {
+    use md5::{Digest, Md5};
+    let mut hasher = Md5::new();
+    hasher.update(bytes);
+    let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap();
+    // The truncated hash is explicitly little-endian, regardless of host
+    // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.)
+    u64::from_le_bytes(hash)
+}
+
+impl<'a> Parser<'a> {
+    /// Reads a sequence of:
+    /// - Length of uncompressed data in bytes, as ULEB128
+    /// - Length of compressed data in bytes (or 0), as ULEB128
+    /// - The indicated number of compressed or uncompressed bytes
+    ///
+    /// If the number of compressed bytes is 0, the subsequent bytes are
+    /// uncompressed. Otherwise, the subsequent bytes are compressed, and will
+    /// be decompressed.
+    ///
+    /// Returns the uncompressed bytes that were read directly or decompressed.
+    pub(crate) fn read_chunk_to_uncompressed_bytes(&mut self) -> anyhow::Result<Cow<'a, [u8]>> {
+        let uncompressed_len = self.read_uleb128_usize()?;
+        let compressed_len = self.read_uleb128_usize()?;
+
+        if compressed_len == 0 {
+            // The bytes are uncompressed, so read them directly.
+            let uncompressed_bytes = self.read_n_bytes(uncompressed_len)?;
+            Ok(Cow::Borrowed(uncompressed_bytes))
+        } else {
+            // The bytes are compressed, so read and decompress them.
+            let compressed_bytes = self.read_n_bytes(compressed_len)?;
+
+            let uncompressed_bytes = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit(
+                compressed_bytes,
+                uncompressed_len,
+            )
+            .map_err(|e| anyhow!("{e:?}"))?;
+            ensure!(uncompressed_bytes.len() == uncompressed_len);
+
+            Ok(Cow::Owned(uncompressed_bytes))
+        }
+    }
+}
diff --git a/src/tools/coverage-dump/src/parser/tests.rs b/src/tools/coverage-dump/src/llvm_utils/tests.rs
index a673606b9c4..506b0a6200b 100644
--- a/src/tools/coverage-dump/src/parser/tests.rs
+++ b/src/tools/coverage-dump/src/llvm_utils/tests.rs
@@ -1,9 +1,5 @@
 use super::unescape_llvm_string_contents;
 
-// WARNING: These tests don't necessarily run in CI, and were mainly used to
-// help track down problems when originally developing this tool.
-// (The tool is still tested indirectly by snapshot tests that rely on it.)
-
 // Tests for `unescape_llvm_string_contents`:
 
 #[test]
diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs
index b21e3e292f2..2c76d2f2460 100644
--- a/src/tools/coverage-dump/src/main.rs
+++ b/src/tools/coverage-dump/src/main.rs
@@ -1,4 +1,6 @@
 mod covfun;
+mod covmap;
+mod llvm_utils;
 mod parser;
 mod prf_names;
 
@@ -17,8 +19,9 @@ fn main() -> anyhow::Result<()> {
     let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?;
     let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?;
 
+    let filename_tables = covmap::make_filename_tables(&llvm_ir)?;
     let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?;
-    crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?;
+    crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?;
 
     Ok(())
 }
diff --git a/src/tools/coverage-dump/src/parser.rs b/src/tools/coverage-dump/src/parser.rs
index 0bd4abdae3e..f26a57b43b3 100644
--- a/src/tools/coverage-dump/src/parser.rs
+++ b/src/tools/coverage-dump/src/parser.rs
@@ -1,38 +1,4 @@
-#[cfg(test)]
-mod tests;
-
-use std::sync::OnceLock;
-
 use anyhow::ensure;
-use regex::bytes;
-
-/// Given the raw contents of a string literal in LLVM IR assembly, decodes any
-/// backslash escapes and returns a vector containing the resulting byte string.
-pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec<u8> {
-    let escape_re = {
-        static RE: OnceLock<bytes::Regex> = OnceLock::new();
-        // LLVM IR supports two string escapes: `\\` and `\xx`.
-        RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap())
-    };
-
-    fn u8_from_hex_digits(digits: &[u8]) -> u8 {
-        // We know that the input contains exactly 2 hex digits, so these calls
-        // should never fail.
-        assert_eq!(digits.len(), 2);
-        let digits = std::str::from_utf8(digits).unwrap();
-        u8::from_str_radix(digits, 16).unwrap()
-    }
-
-    escape_re
-        .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| {
-            let byte = match captures.get(1) {
-                None => b'\\',
-                Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()),
-            };
-            [byte]
-        })
-        .into_owned()
-}
 
 pub(crate) struct Parser<'a> {
     rest: &'a [u8],
diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs
index 96d097c79a3..f9ab35deba5 100644
--- a/src/tools/coverage-dump/src/prf_names.rs
+++ b/src/tools/coverage-dump/src/prf_names.rs
@@ -1,10 +1,10 @@
 use std::collections::HashMap;
 use std::sync::OnceLock;
 
-use anyhow::{anyhow, ensure};
 use regex::Regex;
 
-use crate::parser::{Parser, unescape_llvm_string_contents};
+use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents};
+use crate::parser::Parser;
 
 /// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names`
 /// entries, decodes them, and creates a table that maps name hash values to
@@ -25,18 +25,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
         Some(payload)
     }
 
-    /// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to
-    /// 64 bits as a way to associate data stored in different tables/sections.
-    fn truncated_md5(bytes: &[u8]) -> u64 {
-        use md5::{Digest, Md5};
-        let mut hasher = Md5::new();
-        hasher.update(bytes);
-        let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap();
-        // The truncated hash is explicitly little-endian, regardless of host
-        // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.)
-        u64::from_le_bytes(hash)
-    }
-
     fn demangle_if_able(symbol_name_bytes: &[u8]) -> anyhow::Result<String> {
         // In practice, raw symbol names should always be ASCII.
         let symbol_name_str = std::str::from_utf8(symbol_name_bytes)?;
@@ -54,26 +42,8 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
     for payload in llvm_ir.lines().filter_map(prf_names_payload).map(unescape_llvm_string_contents)
     {
         let mut parser = Parser::new(&payload);
-        let uncompressed_len = parser.read_uleb128_usize()?;
-        let compressed_len = parser.read_uleb128_usize()?;
-
-        let uncompressed_bytes_vec;
-        let uncompressed_bytes: &[u8] = if compressed_len == 0 {
-            // The symbol name bytes are uncompressed, so read them directly.
-            parser.read_n_bytes(uncompressed_len)?
-        } else {
-            // The symbol name bytes are compressed, so read and decompress them.
-            let compressed_bytes = parser.read_n_bytes(compressed_len)?;
-
-            uncompressed_bytes_vec = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit(
-                compressed_bytes,
-                uncompressed_len,
-            )
-            .map_err(|e| anyhow!("{e:?}"))?;
-            ensure!(uncompressed_bytes_vec.len() == uncompressed_len);
-
-            &uncompressed_bytes_vec
-        };
+        let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?;
+        parser.ensure_empty()?;
 
         // Symbol names in the payload are separated by `0x01` bytes.
         for raw_name in uncompressed_bytes.split(|&b| b == 0x01) {
@@ -81,8 +51,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result<HashMap
             let demangled = demangle_if_able(raw_name)?;
             map.insert(hash, demangled);
         }
-
-        parser.ensure_empty()?;
     }
 
     Ok(map)
diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml
index 35be71a46e5..b2976f14a01 100644
--- a/src/tools/features-status-dump/Cargo.toml
+++ b/src/tools/features-status-dump/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 edition = "2021"
 
 [dependencies]
-anyhow = { version = "1", features = ["backtrace"] }
+anyhow = { version = "1" }
 clap = { version = "4", features = ["derive"] }
 serde = { version = "1.0.125", features = [ "derive" ] }
 serde_json = "1.0.59"
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index d6c69d39e17..cacce01675f 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -312,6 +312,7 @@ impl<'a> LintExtractor<'a> {
         if matches!(
             lint.name.as_str(),
             "unused_features" // broken lint
+            | "soft_unstable" // cannot have a stable example
         ) {
             return Ok(());
         }
diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore
index 03c5591b787..ed2d0ba7ba0 100644
--- a/src/tools/miri/.gitignore
+++ b/src/tools/miri/.gitignore
@@ -9,6 +9,9 @@ tex/*/out
 *.mm_profdata
 perf.data
 perf.data.old
-flamegraph.svg
+flamegraph*.svg
+rustc-ice*.txt
 tests/native-lib/libtestlib.so
 .auto-*
+
+/genmc/
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 0d77ca06e1b..739f0702252 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -19,12 +19,10 @@ When you get a review, please take care of the requested changes in new commits.
 existing commits. Generally avoid force-pushing. The only time you should force push is when there
 is a conflict with the master branch (in that case you should rebase across master, not merge), and
 all the way at the end of the review process when the reviewer tells you that the PR is done and you
-should squash the commits. For the latter case, use `git rebase --keep-base ...` to squash without
-changing the base commit your PR branches off of. Use your own judgment and the reviewer's guidance
-to decide whether the PR should be squashed into a single commit or multiple logically separate
-commits. (All this is to work around the fact that Github is quite bad at dealing with force pushes
-and does not support `git range-diff`. Maybe one day Github will be good at git and then life can
-become easier.)
+should squash the commits. If you are unsure how to use `git rebase` to squash commits, use `./miri
+squash` which automates the process but leaves little room for customization. (All this is to work
+around the fact that Github is quite bad at dealing with force pushes and does not support `git
+range-diff`. Maybe one day Github will be good at git and then life can become easier.)
 
 Most PRs bounce back and forth between the reviewer and the author several times, so it is good to
 keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index bb24e700e73..e4d7abdb0f7 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -6,7 +6,7 @@ name = "miri"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
 default-run = "miri"
-edition = "2021"
+edition = "2024"
 
 [lib]
 test = true     # we have unit tests
@@ -65,6 +65,7 @@ harness = false
 
 [features]
 default = ["stack-cache"]
+genmc = []
 stack-cache = []
 stack-cache-consistency-check = ["stack-cache"]
 
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 95e1770aa7b..122438a2509 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -277,22 +277,15 @@ Try running `cargo miri clean`.
 Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS`
 environment variable. We first document the most relevant and most commonly used flags:
 
-* `-Zmiri-address-reuse-rate=<rate>` changes the probability that a freed *non-stack* allocation
-  will be added to the pool for address reuse, and the probability that a new *non-stack* allocation
-  will be taken from the pool. Stack allocations never get added to or taken from the pool. The
-  default is `0.5`.
-* `-Zmiri-address-reuse-cross-thread-rate=<rate>` changes the probability that an allocation which
-  attempts to reuse a previously freed block of memory will also consider blocks freed by *other
-  threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse
-  attempt is made, only addresses from the same thread will be considered. Reusing an address from
-  another thread induces synchronization between those threads, which can mask data races and weak
-  memory bugs.
-* `-Zmiri-compare-exchange-weak-failure-rate=<rate>` changes the failure rate of
-  `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail).
-  You can change it to any value between `0.0` and `1.0`, where `1.0` means it
-  will always fail and `0.0` means it will never fail. Note that setting it to
-  `1.0` will likely cause hangs, since it means programs using
-  `compare_exchange_weak` cannot make progress.
+* `-Zmiri-deterministic-concurrency` makes Miri's concurrency-related behavior fully deterministic.
+  Strictly speaking, Miri is always fully deterministic when isolation is enabled (the default
+  mode), but this determinism is achieved by using an RNG with a fixed seed. Seemingly harmless
+  changes to the program, or just running it for a different target architecture, can thus lead to
+  completely different program behavior down the line. This flag disables the use of an RNG for
+  concurrency-related decisions. Therefore, Miri cannot find bugs that only occur under some
+  specific circumstances, but Miri's behavior will also be more stable across versions and targets.
+  This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0
+  -Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`.
 * `-Zmiri-disable-isolation` disables host isolation. As a consequence,
   the program has access to host resources such as environment variables, file
   systems, and randomness.
@@ -334,9 +327,6 @@ environment variable. We first document the most relevant and most commonly used
   This will necessarily miss some bugs as those operations are not efficiently and accurately
   implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is
   subject to these operations.
-* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active
-  thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables
-  preemption.
 * `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can
   tell what it is doing when a program just keeps running. You can customize how frequently the
   report is printed via `-Zmiri-report-progress=<blocks>`, which prints the report every N basic
@@ -365,6 +355,22 @@ The remaining flags are for advanced use only, and more likely to change or be r
 Some of these are **unsound**, which means they can lead
 to Miri failing to detect cases of undefined behavior in a program.
 
+* `-Zmiri-address-reuse-rate=<rate>` changes the probability that a freed *non-stack* allocation
+  will be added to the pool for address reuse, and the probability that a new *non-stack* allocation
+  will be taken from the pool. Stack allocations never get added to or taken from the pool. The
+  default is `0.5`.
+* `-Zmiri-address-reuse-cross-thread-rate=<rate>` changes the probability that an allocation which
+  attempts to reuse a previously freed block of memory will also consider blocks freed by *other
+  threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse
+  attempt is made, only addresses from the same thread will be considered. Reusing an address from
+  another thread induces synchronization between those threads, which can mask data races and weak
+  memory bugs.
+* `-Zmiri-compare-exchange-weak-failure-rate=<rate>` changes the failure rate of
+  `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail).
+  You can change it to any value between `0.0` and `1.0`, where `1.0` means it
+  will always fail and `0.0` means it will never fail. Note that setting it to
+  `1.0` will likely cause hangs, since it means programs using
+  `compare_exchange_weak` cannot make progress.
 * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you
   can focus on other failures, but it means Miri can miss bugs in your program.
   Using this flag is **unsound**.
@@ -383,6 +389,13 @@ to Miri failing to detect cases of undefined behavior in a program.
   this flag is **unsound**.
 * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak
   memory effects.
+* `-Zmiri-fixed-schedule` disables preemption (like `-Zmiri-preemption-rate=0.0`) and furthermore
+  disables the randomization of the next thread to be picked, instead fixing a round-robin schedule.
+  Note however that other aspects of Miri's concurrency behavior are still randomize; use
+  `-Zmiri-deterministic-concurrency` to disable them all.
+* `-Zmiri-force-intrinsic-fallback` forces the use of the "fallback" body for all intrinsics that
+  have one. This is useful to test the fallback bodies, but should not be used otherwise. It is
+  **unsound** since the fallback body might not be checking for all UB.
 * `-Zmiri-native-lib=<path to a shared object file>` is an experimental flag for providing support
   for calling native functions from inside the interpreter via FFI. The flag is supported only on
   Unix systems. Functions not provided by that file are still executed via the usual Miri shims.
@@ -412,6 +425,10 @@ to Miri failing to detect cases of undefined behavior in a program.
   without an explicit value), `none` means it never recurses, `scalar` means it only recurses for
   types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as
   individual scalars or pairs of scalars). Setting this to `none` is **unsound**.
+* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active
+  thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables
+  preemption. Note that even without preemption, the schedule is still non-deterministic:
+  if a thread blocks or yields, the next thread is chosen randomly.
 * `-Zmiri-provenance-gc=<blocks>` configures how often the pointer provenance garbage collector runs.
   The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting
   this to `0` disables the garbage collector, which causes some programs to have explosive memory
@@ -443,9 +460,6 @@ to Miri failing to detect cases of undefined behavior in a program.
   casts are not supported in this mode, but that may change in the future.
 * `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
   `4` is default for most targets. This value should always be a power of 2 and nonzero.
-* `-Zmiri-unique-is-unique` performs additional aliasing checks for `core::ptr::Unique` to ensure
-  that it could theoretically be considered `noalias`. This flag is experimental and has
-  an effect only when used with `-Zmiri-tree-borrows`.
 
 [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
 
@@ -566,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/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
index 5b807ac3df1..89797c49820 100644
--- a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs
@@ -7,10 +7,7 @@ fn main() {
     // We can't use too big of an allocation or this code will encounter an allocation failure in
     // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect
     // we're trying to measure is clearly visible above the interpreter's startup time.
-    // FIXME (https://github.com/rust-lang/miri/issues/4253): On 32bit targets, we can run out of
-    // usable addresses if we don't reuse, leading to random test failures.
-    let count = if cfg!(target_pointer_width = "32") { 8 } else { 12 };
-    for _ in 0..count {
+    for _ in 0..20 {
         drop(Vec::<u8>::with_capacity(512 * 1024 * 1024));
     }
 }
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index ed142b0e211..23048914af1 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 name = "cargo-miri"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [[bin]]
 name = "cargo-miri"
diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs
index 322ef0a6c2a..4c01a81fdfd 100644
--- a/src/tools/miri/cargo-miri/src/main.rs
+++ b/src/tools/miri/cargo-miri/src/main.rs
@@ -63,27 +63,37 @@ fn main() {
         return;
     }
 
+    let Some(first) = args.next() else {
+        show_error!(
+            "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`"
+        )
+    };
+
     // The way rustdoc invokes rustc is indistinguishable from the way cargo invokes rustdoc by the
     // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate.
     if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() {
         // ...however, we then also see this variable when rustdoc invokes us as the testrunner!
-        // The runner is invoked as `$runtool ($runtool-arg)* output_file`;
-        // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to
-        // the test-builder unconditionally, we can just check the number of remaining arguments:
-        if args.len() == 1 {
-            phase_runner(args, RunnerPhase::Rustdoc);
-        } else {
-            phase_rustc(args, RustcPhase::Rustdoc);
+        // In that case the first argument is `runner` and there are no more arguments.
+        match first.as_str() {
+            "runner" => phase_runner(args, RunnerPhase::Rustdoc),
+            flag if flag.starts_with("--") || flag.starts_with("@") => {
+                // This is probably rustdoc invoking us to build the test. But we need to get `first`
+                // "back onto the iterator", it is some part of the rustc invocation.
+                phase_rustc(iter::once(first).chain(args), RustcPhase::Rustdoc);
+            }
+            _ => {
+                show_error!(
+                    "`cargo-miri` failed to recognize which phase of the build process this is, please report a bug.\n\
+                    We are inside MIRI_CALLED_FROM_RUSTDOC.\n\
+                    The command-line arguments were: {:#?}",
+                    Vec::from_iter(env::args()),
+                );
+            }
         }
 
         return;
     }
 
-    let Some(first) = args.next() else {
-        show_error!(
-            "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`"
-        )
-    };
     match first.as_str() {
         "miri" => phase_cargo_miri(args),
         "runner" => phase_runner(args, RunnerPhase::Cargo),
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index cb62e12413c..4857f62cd3a 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -176,6 +176,11 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
     // Set `--target-dir` to `miri` inside the original target directory.
     let target_dir = get_target_dir(&metadata);
     cmd.arg("--target-dir").arg(target_dir);
+    // Only when running in x.py (where we are running with beta cargo): set `RUSTC_STAGE`.
+    // Will have to be removed on next bootstrap bump. tag: cfg(bootstrap).
+    if env::var_os("RUSTC_STAGE").is_some() {
+        cmd.arg("-Zdoctest-xcompile");
+    }
 
     // *After* we set all the flags that need setting, forward everything else. Make sure to skip
     // `--target-dir` (which would otherwise be set twice).
@@ -666,11 +671,6 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
         if arg == "--extern" {
             // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
             forward_patched_extern_arg(&mut args, &mut cmd);
-        } else if arg == "--test-runtool" {
-            // An existing --test-runtool flag indicates cargo is running in cross-target mode, which we don't support.
-            // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
-            // otherwise, we won't be called as rustdoc at all.
-            show_error!("cross-interpreting doctests is not currently supported by Miri.");
         } else {
             cmd.arg(arg);
         }
@@ -702,10 +702,10 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
     // make sure the 'miri' flag is set for rustdoc
     cmd.arg("--cfg").arg("miri");
 
-    // Make rustdoc call us back.
+    // Make rustdoc call us back for the build.
+    // (cargo already sets `--test-runtool` to us since we are the cargo test runner.)
     let cargo_miri_path = env::current_exe().expect("current executable path invalid");
     cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments
-    cmd.arg("--test-runtool").arg(&cargo_miri_path); // invoked with just a single path argument
 
     debug_cmd("[cargo-miri rustdoc]", verbose, &cmd);
     exec(cmd)
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index 7afc8481009..b9b58c04f9e 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -24,11 +24,9 @@ pub fn setup(
     let ask_user = !only_setup;
     let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
     let show_setup = only_setup && !print_sysroot;
-    if !only_setup {
-        if let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") {
-            // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
-            return sysroot.into();
-        }
+    if !only_setup && let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") {
+        // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
+        return sysroot.into();
     }
 
     // Determine where the rust sources are located.  The env var trumps auto-detection.
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index a04898de6ab..462a9cc62bf 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -6,7 +6,7 @@ name = "miri-script"
 repository = "https://github.com/rust-lang/miri"
 version = "0.1.0"
 default-run = "miri-script"
-edition = "2021"
+edition = "2024"
 
 [workspace]
 # We make this a workspace root so that cargo does not go looking in ../Cargo.toml for the workspace root.
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 17a7c06b525..3b7b159aeab 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -1,7 +1,8 @@
 use std::collections::HashMap;
 use std::ffi::{OsStr, OsString};
-use std::fs::File;
-use std::io::{BufReader, BufWriter, Write};
+use std::fmt::Write as _;
+use std::fs::{self, File};
+use std::io::{self, BufRead, BufReader, BufWriter, Write as _};
 use std::ops::Not;
 use std::path::PathBuf;
 use std::time::Duration;
@@ -169,7 +170,8 @@ impl Command {
             | Command::Toolchain { .. }
             | Command::Bench { .. }
             | Command::RustcPull { .. }
-            | Command::RustcPush { .. } => {}
+            | Command::RustcPush { .. }
+            | Command::Squash => {}
         }
         // Then run the actual command.
         match self {
@@ -188,6 +190,7 @@ impl Command {
             Command::Toolchain { flags } => Self::toolchain(flags),
             Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
             Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
+            Command::Squash => Self::squash(),
         }
     }
 
@@ -383,6 +386,72 @@ impl Command {
         Ok(())
     }
 
+    fn squash() -> Result<()> {
+        let sh = Shell::new()?;
+        sh.change_dir(miri_dir()?);
+        // Figure out base wrt latest upstream master.
+        // (We can't trust any of the local ones, they can all be outdated.)
+        let origin_master = {
+            cmd!(sh, "git fetch https://github.com/rust-lang/miri/")
+                .quiet()
+                .ignore_stdout()
+                .ignore_stderr()
+                .run()?;
+            cmd!(sh, "git rev-parse FETCH_HEAD").read()?
+        };
+        let base = cmd!(sh, "git merge-base HEAD {origin_master}").read()?;
+        // Rebase onto that, setting ourselves as the sequence editor so that we can edit the sequence programmatically.
+        // We want to forward the host stdin so apparently we cannot use `cmd!`.
+        let mut cmd = process::Command::new("git");
+        cmd.arg("rebase").arg(&base).arg("--interactive");
+        cmd.env("GIT_SEQUENCE_EDITOR", env::current_exe()?);
+        cmd.env("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR", "1");
+        cmd.current_dir(sh.current_dir());
+        let result = cmd.status()?;
+        if !result.success() {
+            bail!("`git rebase` failed");
+        }
+        Ok(())
+    }
+
+    pub fn squash_sequence_editor() -> Result<()> {
+        let sequence_file = env::args().nth(1).expect("git should pass us a filename");
+        if sequence_file == "fmt" {
+            // This is probably us being called as a git hook as part of the rebase. Let's just
+            // ignore this. Sadly `git rebase` does not have a flag to skip running hooks.
+            return Ok(());
+        }
+        // Read the provided sequence and adjust it.
+        let rebase_sequence = {
+            let mut rebase_sequence = String::new();
+            let file = fs::File::open(&sequence_file).with_context(|| {
+                format!("failed to read rebase sequence from {sequence_file:?}")
+            })?;
+            let file = io::BufReader::new(file);
+            for line in file.lines() {
+                let line = line?;
+                // The first line is left unchanged.
+                if rebase_sequence.is_empty() {
+                    writeln!(rebase_sequence, "{line}").unwrap();
+                    continue;
+                }
+                // If this is a "pick" like, make it "squash".
+                if let Some(rest) = line.strip_prefix("pick ") {
+                    writeln!(rebase_sequence, "squash {rest}").unwrap();
+                    continue;
+                }
+                // We've reached the end of the relevant part of the sequence, and we can stop.
+                break;
+            }
+            rebase_sequence
+        };
+        // Write out the adjusted sequence.
+        fs::write(&sequence_file, rebase_sequence).with_context(|| {
+            format!("failed to write adjusted rebase sequence to {sequence_file:?}")
+        })?;
+        Ok(())
+    }
+
     fn bench(
         target: Option<String>,
         no_install: bool,
@@ -606,11 +675,9 @@ impl Command {
         let mut early_flags = Vec::<OsString>::new();
 
         // In `dep` mode, the target is already passed via `MIRI_TEST_TARGET`
-        if !dep {
-            if let Some(target) = &target {
-                early_flags.push("--target".into());
-                early_flags.push(target.into());
-            }
+        if !dep && let Some(target) = &target {
+            early_flags.push("--target".into());
+            early_flags.push(target.into());
         }
         early_flags.push("--edition".into());
         early_flags.push(edition.as_deref().unwrap_or("2021").into());
@@ -638,10 +705,8 @@ impl Command {
         // Add Miri flags
         let mut cmd = cmd.args(&miri_flags).args(&early_flags).args(&flags);
         // For `--dep` we also need to set the target in the env var.
-        if dep {
-            if let Some(target) = &target {
-                cmd = cmd.env("MIRI_TEST_TARGET", target);
-            }
+        if dep && let Some(target) = &target {
+            cmd = cmd.env("MIRI_TEST_TARGET", target);
         }
         // Finally, run the thing.
         Ok(cmd.run()?)
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index 279bdf8cc3f..6aab2f79bd7 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -133,6 +133,8 @@ pub enum Command {
         #[arg(default_value = "miri-sync")]
         branch: String,
     },
+    /// Squash the commits of the current feature branch into one.
+    Squash,
 }
 
 impl Command {
@@ -154,7 +156,7 @@ impl Command {
                 flags.extend(remainder);
                 Ok(())
             }
-            Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } =>
+            Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } | Self::Squash =>
                 bail!("unexpected \"--\" found in arguments"),
         }
     }
@@ -170,6 +172,11 @@ pub struct Cli {
 }
 
 fn main() -> Result<()> {
+    // If we are invoked as the git sequence editor, jump to that logic.
+    if !std::env::var_os("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR").unwrap_or_default().is_empty() {
+        return Command::squash_sequence_editor();
+    }
+
     // Split the arguments into the part before the `--` and the part after.
     // The `--` itself ends up in the second part.
     let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect();
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index c039b4827ee..5c2a055990f 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -213,7 +213,7 @@ impl MiriEnv {
             let toolchain = &self.toolchain;
             let mut cmd = cmd!(
                 self.sh,
-                "rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
+                "rustfmt +{toolchain} --edition=2024 --config-path {config_path} --unstable-features --skip-children {flags...}"
             );
             if first {
                 // Log an abbreviating command, and only once.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 59d53891217..8b98fe3c4fc 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-1b8ab72680f36e783af84c1a3c4f8508572bd9f9
+ac17c3486c6fdfbb0c3c18b99f3d8dfbff625d29
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index 335e8d76999..dd389d97cdc 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -114,8 +114,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         memory_kind: MemoryKind,
     ) -> InterpResult<'tcx, u64> {
         let this = self.eval_context_ref();
-        let mut rng = this.machine.rng.borrow_mut();
         let info = this.get_alloc_info(alloc_id);
+
+        // Miri's address assignment leaks state across thread boundaries, which is incompatible
+        // with GenMC execution. So we instead let GenMC assign addresses to allocations.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?;
+            return interp_ok(addr);
+        }
+
+        let mut rng = this.machine.rng.borrow_mut();
         // This is either called immediately after allocation (and then cached), or when
         // adjusting `tcx` pointers (which never get freed). So assert that we are looking
         // at a live allocation. This also ensures that we never re-assign an address to an
@@ -197,6 +205,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if global_state.next_base_addr > this.target_usize_max() {
                 throw_exhaust!(AddressSpaceFull);
             }
+            // If we filled up more than half the address space, start aggressively reusing
+            // addresses to avoid running out.
+            if global_state.next_base_addr > u64::try_from(this.target_isize_max()).unwrap() {
+                global_state.reuse.address_space_shortage();
+            }
 
             interp_ok(base_addr)
         }
@@ -490,7 +503,7 @@ impl<'tcx> MiriMachine<'tcx> {
         // Also remember this address for future reuse.
         let thread = self.threads.active_thread();
         global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || {
-            if let Some(data_race) = &self.data_race {
+            if let Some(data_race) = self.data_race.as_vclocks_ref() {
                 data_race.release_clock(&self.threads, |clock| clock.clone())
             } else {
                 VClock::default()
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index c0d24a9fbbc..29d4f2bb7b0 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -20,7 +20,7 @@ pub struct ReusePool {
     /// allocations as address-size pairs, the list must be sorted by the size and then the thread ID.
     ///
     /// Each of these maps has at most MAX_POOL_SIZE elements, and since alignment is limited to
-    /// less than 64 different possible value, that bounds the overall size of the pool.
+    /// less than 64 different possible values, that bounds the overall size of the pool.
     ///
     /// We also store the ID and the data-race clock of the thread that donated this pool element,
     /// to ensure synchronization with the thread that picks up this address.
@@ -36,6 +36,15 @@ impl ReusePool {
         }
     }
 
+    /// Call this when we are using up a lot of the address space: if memory reuse is enabled at all,
+    /// this will bump the intra-thread reuse rate to 100% so that we can keep running this program as
+    /// long as possible.
+    pub fn address_space_shortage(&mut self) {
+        if self.address_reuse_rate > 0.0 {
+            self.address_reuse_rate = 1.0;
+        }
+    }
+
     fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> {
         let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap();
         if self.pool.len() <= pool_idx {
@@ -55,9 +64,7 @@ impl ReusePool {
         clock: impl FnOnce() -> VClock,
     ) {
         // Let's see if we even want to remember this address.
-        // We don't remember stack addresses: there's a lot of them (so the perf impact is big),
-        // and we only want to reuse stack slots within the same thread or else we'll add a lot of
-        // undesired synchronization.
+        // We don't remember stack addresses since there's so many of them (so the perf impact is big).
         if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) {
             return;
         }
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 8ff1c9d6ff0..469fc264970 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -28,13 +28,14 @@ use std::env::{self, VarError};
 use std::num::NonZero;
 use std::ops::Range;
 use std::path::PathBuf;
+use std::rc::Rc;
 use std::str::FromStr;
 use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
 use std::sync::{Arc, Once};
 
 use miri::{
-    BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields,
-    ValidationMode,
+    BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType,
+    ProvenanceMode, RetagFields, ValidationMode,
 };
 use rustc_abi::ExternAbi;
 use rustc_data_structures::sync;
@@ -60,6 +61,8 @@ use tracing::debug;
 struct MiriCompilerCalls {
     miri_config: Option<MiriConfig>,
     many_seeds: Option<ManySeedsConfig>,
+    /// Settings for using GenMC with Miri.
+    genmc_config: Option<GenmcConfig>,
 }
 
 struct ManySeedsConfig {
@@ -68,8 +71,12 @@ struct ManySeedsConfig {
 }
 
 impl MiriCompilerCalls {
-    fn new(miri_config: MiriConfig, many_seeds: Option<ManySeedsConfig>) -> Self {
-        Self { miri_config: Some(miri_config), many_seeds }
+    fn new(
+        miri_config: MiriConfig,
+        many_seeds: Option<ManySeedsConfig>,
+        genmc_config: Option<GenmcConfig>,
+    ) -> Self {
+        Self { miri_config: Some(miri_config), many_seeds, genmc_config }
     }
 }
 
@@ -179,6 +186,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                     optimizations is usually marginal at best.");
         }
 
+        if let Some(genmc_config) = &self.genmc_config {
+            let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config));
+
+            todo!("GenMC mode not yet implemented");
+        };
+
         if let Some(many_seeds) = self.many_seeds.take() {
             assert!(config.seed.is_none());
             let exit_code = sync::IntoDynSyncSend(AtomicI32::new(rustc_driver::EXIT_SUCCESS));
@@ -187,8 +200,14 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 let mut config = config.clone();
                 config.seed = Some((*seed).into());
                 eprintln!("Trying seed: {seed}");
-                let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
-                    .unwrap_or(rustc_driver::EXIT_FAILURE);
+                let return_code = miri::eval_entry(
+                    tcx,
+                    entry_def_id,
+                    entry_type,
+                    &config,
+                    /* genmc_ctx */ None,
+                )
+                .unwrap_or(rustc_driver::EXIT_FAILURE);
                 if return_code != rustc_driver::EXIT_SUCCESS {
                     eprintln!("FAILING SEED: {seed}");
                     if !many_seeds.keep_going {
@@ -206,11 +225,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             }
             std::process::exit(exit_code.0.into_inner());
         } else {
-            let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config)
+            let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
                 .unwrap_or_else(|| {
                     tcx.dcx().abort_if_errors();
                     rustc_driver::EXIT_FAILURE
                 });
+
             std::process::exit(return_code);
         }
 
@@ -439,7 +459,7 @@ fn jemalloc_magic() {
     // linking, so we need to explicitly depend on the function.
     #[cfg(target_os = "macos")]
     {
-        extern "C" {
+        unsafe extern "C" {
             fn _rjem_je_zone_register();
         }
 
@@ -506,6 +526,7 @@ fn main() {
     let mut many_seeds_keep_going = false;
     let mut miri_config = MiriConfig::default();
     miri_config.env = env_snapshot;
+    let mut genmc_config = None;
 
     let mut rustc_args = vec![];
     let mut after_dashdash = false;
@@ -533,8 +554,6 @@ fn main() {
         } else if arg == "-Zmiri-tree-borrows" {
             miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows);
             miri_config.provenance_mode = ProvenanceMode::Strict;
-        } else if arg == "-Zmiri-unique-is-unique" {
-            miri_config.unique_is_unique = true;
         } else if arg == "-Zmiri-disable-data-race-detector" {
             miri_config.data_race_detector = false;
             miri_config.weak_memory_emulation = false;
@@ -565,6 +584,8 @@ fn main() {
         } else if arg == "-Zmiri-ignore-leaks" {
             miri_config.ignore_leaks = true;
             miri_config.collect_leak_backtraces = false;
+        } else if arg == "-Zmiri-force-intrinsic-fallback" {
+            miri_config.force_intrinsic_fallback = true;
         } else if arg == "-Zmiri-strict-provenance" {
             miri_config.provenance_mode = ProvenanceMode::Strict;
         } else if arg == "-Zmiri-permissive-provenance" {
@@ -573,6 +594,13 @@ fn main() {
             miri_config.mute_stdout_stderr = true;
         } else if arg == "-Zmiri-retag-fields" {
             miri_config.retag_fields = RetagFields::Yes;
+        } else if arg == "-Zmiri-fixed-schedule" {
+            miri_config.fixed_scheduling = true;
+        } else if arg == "-Zmiri-deterministic-concurrency" {
+            miri_config.fixed_scheduling = true;
+            miri_config.address_reuse_cross_thread_rate = 0.0;
+            miri_config.cmpxchg_weak_failure_rate = 0.0;
+            miri_config.weak_memory_emulation = false;
         } else if let Some(retag_fields) = arg.strip_prefix("-Zmiri-retag-fields=") {
             miri_config.retag_fields = match retag_fields {
                 "all" => RetagFields::Yes,
@@ -596,6 +624,10 @@ fn main() {
             many_seeds = Some(0..64);
         } else if arg == "-Zmiri-many-seeds-keep-going" {
             many_seeds_keep_going = true;
+        } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") {
+            // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking.
+            miri_config.borrow_tracker = None;
+            GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg);
         } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") {
             miri_config.forwarded_env_vars.push(param.to_owned());
         } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") {
@@ -690,14 +722,6 @@ fn main() {
             rustc_args.push(arg);
         }
     }
-    // `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows`
-    if miri_config.unique_is_unique
-        && !matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows))
-    {
-        show_error!(
-            "-Zmiri-unique-is-unique only has an effect when -Zmiri-tree-borrows is also used"
-        );
-    }
     // Tree Borrows implies strict provenance, and is not compatible with native calls.
     if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) {
         if miri_config.provenance_mode != ProvenanceMode::Strict {
@@ -727,7 +751,24 @@ fn main() {
     let many_seeds =
         many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
 
+    // Validate settings for data race detection and GenMC mode.
+    assert_eq!(genmc_config.is_some(), miri_config.genmc_mode);
+    if genmc_config.is_some() {
+        if !miri_config.data_race_detector {
+            show_error!("Cannot disable data race detection in GenMC mode (currently)");
+        } else if !miri_config.weak_memory_emulation {
+            show_error!("Cannot disable weak memory emulation in GenMC mode");
+        }
+    } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector {
+        show_error!(
+            "Weak memory emulation cannot be enabled when the data race detector is disabled"
+        );
+    };
+
     debug!("rustc arguments: {:?}", rustc_args);
     debug!("crate arguments: {:?}", miri_config.args);
-    run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
+    run_compiler_and_exit(
+        &rustc_args,
+        &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config),
+    )
 }
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 9808102f4ba..b66c561d2b8 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -102,8 +102,6 @@ pub struct GlobalStateInner {
     tracked_pointer_tags: FxHashSet<BorTag>,
     /// Whether to recurse into datatypes when searching for pointers to retag.
     retag_fields: RetagFields,
-    /// Whether `core::ptr::Unique` gets special (`Box`-like) handling.
-    unique_is_unique: bool,
 }
 
 impl VisitProvenance for GlobalStateInner {
@@ -164,7 +162,6 @@ impl GlobalStateInner {
         borrow_tracker_method: BorrowTrackerMethod,
         tracked_pointer_tags: FxHashSet<BorTag>,
         retag_fields: RetagFields,
-        unique_is_unique: bool,
     ) -> Self {
         GlobalStateInner {
             borrow_tracker_method,
@@ -173,7 +170,6 @@ impl GlobalStateInner {
             protected_tags: FxHashMap::default(),
             tracked_pointer_tags,
             retag_fields,
-            unique_is_unique,
         }
     }
 
@@ -239,7 +235,6 @@ impl BorrowTrackerMethod {
             self,
             config.tracked_pointer_tags.clone(),
             config.retag_fields,
-            config.unique_is_unique,
         ))
     }
 }
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 18a5a0612bb..bc57ba697b3 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -594,7 +594,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Option<Provenance>> {
         let this = self.eval_context_mut();
         // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
-        this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::InboundsTest)?;
+        this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::Dereferenceable)?;
 
         // It is crucial that this gets called on all code paths, to ensure we track tag creation.
         let log_creation = |this: &MiriInterpCx<'tcx>,
@@ -740,7 +740,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                 if let Some(access) = access {
                     assert_eq!(access, AccessKind::Write);
                     // Make sure the data race model also knows about this.
-                    if let Some(data_race) = alloc_extra.data_race.as_mut() {
+                    if let Some(data_race) = alloc_extra.data_race.as_vclocks_mut() {
                         data_race.write(
                             alloc_id,
                             range,
@@ -789,7 +789,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                     if let Some(access) = access {
                         assert_eq!(access, AccessKind::Read);
                         // Make sure the data race model also knows about this.
-                        if let Some(data_race) = alloc_extra.data_race.as_ref() {
+                        if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
                             data_race.read(
                                 alloc_id,
                                 range,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index b2fd9b2bf05..f5a0013047a 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -179,7 +179,7 @@ impl NodeDebugInfo {
     /// Add a name to the tag. If a same tag is associated to several pointers,
     /// it can have several names which will be separated by commas.
     pub fn add_name(&mut self, name: &str) {
-        if let Some(ref mut prev_name) = &mut self.name {
+        if let Some(prev_name) = &mut self.name {
             prev_name.push_str(", ");
             prev_name.push_str(name);
         } else {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index f39a606513d..f3e32e75f2f 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -2,7 +2,6 @@ use rustc_abi::{BackendRepr, Size};
 use rustc_middle::mir::{Mutability, RetagKind};
 use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::def_id::DefId;
 
 use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
 use crate::concurrency::data_race::NaReadType;
@@ -115,14 +114,15 @@ impl<'tcx> Tree {
 /// Policy for a new borrow.
 #[derive(Debug, Clone, Copy)]
 struct NewPermission {
-    /// Optionally ignore the actual size to do a zero-size reborrow.
-    /// If this is set then `dereferenceable` is not enforced.
-    zero_size: bool,
     /// Which permission should the pointer start with.
     initial_state: Permission,
     /// Whether this pointer is part of the arguments of a function call.
     /// `protector` is `Some(_)` for all pointers marked `noalias`.
     protector: Option<ProtectorKind>,
+    /// Whether a read should be performed on a retag.  This should be `false`
+    /// for `Cell` because this could cause data races when using thread-safe
+    /// data types like `Mutex<T>`.
+    initial_read: bool,
 }
 
 impl<'tcx> NewPermission {
@@ -141,18 +141,19 @@ impl<'tcx> NewPermission {
         // To eliminate the case of Protected Reserved IM we override interior mutability
         // in the case of a protected reference: protected references are always considered
         // "freeze" in their reservation phase.
-        let initial_state = match mutability {
-            Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze, is_protected),
-            Mutability::Not if ty_is_freeze => Permission::new_frozen(),
+        let (initial_state, initial_read) = match mutability {
+            Mutability::Mut if ty_is_unpin =>
+                (Permission::new_reserved(ty_is_freeze, is_protected), true),
+            Mutability::Not if ty_is_freeze => (Permission::new_frozen(), true),
+            Mutability::Not if !ty_is_freeze => (Permission::new_cell(), false),
             // Raw pointers never enter this function so they are not handled.
             // However raw pointers are not the only pointers that take the parent
-            // tag, this also happens for `!Unpin` `&mut`s and interior mutable
-            // `&`s, which are excluded above.
+            // tag, this also happens for `!Unpin` `&mut`s, which are excluded above.
             _ => return None,
         };
 
         let protector = is_protected.then_some(ProtectorKind::StrongProtector);
-        Some(Self { zero_size: false, initial_state, protector })
+        Some(Self { initial_state, protector, initial_read })
     }
 
     /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
@@ -162,19 +163,18 @@ impl<'tcx> NewPermission {
         ty: Ty<'tcx>,
         kind: RetagKind,
         cx: &crate::MiriInterpCx<'tcx>,
-        zero_size: bool,
     ) -> Option<Self> {
         let pointee = ty.builtin_deref(true).unwrap();
         pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
             // Regular `Unpin` box, give it `noalias` but only a weak protector
             // because it is valid to deallocate it within the function.
-            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env());
+            let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
             let protected = kind == RetagKind::FnEntry;
             let initial_state = Permission::new_reserved(ty_is_freeze, protected);
             Self {
-                zero_size,
                 initial_state,
                 protector: protected.then_some(ProtectorKind::WeakProtector),
+                initial_read: true,
             }
         })
     }
@@ -197,7 +197,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Make sure the new permission makes sense as the initial permission of a fresh tag.
         assert!(new_perm.initial_state.is_initial());
         // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
-        this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::InboundsTest)?;
+        this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::Dereferenceable)?;
 
         // It is crucial that this gets called on all code paths, to ensure we track tag creation.
         let log_creation = |this: &MiriInterpCx<'tcx>,
@@ -289,13 +289,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
 
         // All reborrows incur a (possibly zero-sized) read access to the parent
-        tree_borrows.perform_access(
-            orig_tag,
-            Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
-            this.machine.borrow_tracker.as_ref().unwrap(),
-            alloc_id,
-            this.machine.current_span(),
-        )?;
+        if new_perm.initial_read {
+            tree_borrows.perform_access(
+                orig_tag,
+                Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
+                this.machine.borrow_tracker.as_ref().unwrap(),
+                alloc_id,
+                this.machine.current_span(),
+            )?;
+        }
         // Record the parent-child pair in the tree.
         tree_borrows.new_child(
             orig_tag,
@@ -308,8 +310,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         drop(tree_borrows);
 
         // Also inform the data race model (but only if any bytes are actually affected).
-        if range.size.bytes() > 0 {
-            if let Some(data_race) = alloc_extra.data_race.as_ref() {
+        if range.size.bytes() > 0 && new_perm.initial_read {
+            if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
                 data_race.read(
                     alloc_id,
                     range,
@@ -333,15 +335,12 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Determine the size of the reborrow.
         // For most types this is the entire size of the place, however
         // - when `extern type` is involved we use the size of the known prefix,
-        // - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set
-        // then we override the size to do a zero-length reborrow.
-        let reborrow_size = match new_perm {
-            NewPermission { zero_size: false, .. } =>
-                this.size_and_align_of_mplace(place)?
-                    .map(|(size, _)| size)
-                    .unwrap_or(place.layout.size),
-            _ => Size::from_bytes(0),
-        };
+        // - if the pointer is not reborrowed (raw pointer) then we override the size
+        //   to do a zero-length reborrow.
+        let reborrow_size = this
+            .size_and_align_of_mplace(place)?
+            .map(|(size, _)| size)
+            .unwrap_or(place.layout.size);
         trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
 
         // This new tag is not guaranteed to actually be used.
@@ -405,9 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let options = this.machine.borrow_tracker.as_mut().unwrap().get_mut();
         let retag_fields = options.retag_fields;
-        let unique_did =
-            options.unique_is_unique.then(|| this.tcx.lang_items().ptr_unique()).flatten();
-        let mut visitor = RetagVisitor { ecx: this, kind, retag_fields, unique_did };
+        let mut visitor = RetagVisitor { ecx: this, kind, retag_fields };
         return visitor.visit_value(place);
 
         // The actual visitor.
@@ -415,7 +412,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             ecx: &'ecx mut MiriInterpCx<'tcx>,
             kind: RetagKind,
             retag_fields: RetagFields,
-            unique_did: Option<DefId>,
         }
         impl<'ecx, 'tcx> RetagVisitor<'ecx, 'tcx> {
             #[inline(always)] // yes this helps in our benchmarks
@@ -446,12 +442,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
                 // Only boxes for the global allocator get any special treatment.
                 if box_ty.is_box_global(*self.ecx.tcx) {
-                    let new_perm = NewPermission::from_unique_ty(
-                        place.layout.ty,
-                        self.kind,
-                        self.ecx,
-                        /* zero_size */ false,
-                    );
+                    let new_perm =
+                        NewPermission::from_unique_ty(place.layout.ty, self.kind, self.ecx);
                     self.retag_ptr_inplace(place, new_perm)?;
                 }
                 interp_ok(())
@@ -485,16 +477,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // even if field retagging is not enabled. *shrug*)
                         self.walk_value(place)?;
                     }
-                    ty::Adt(adt, _) if self.unique_did == Some(adt.did()) => {
-                        let place = inner_ptr_of_unique(self.ecx, place)?;
-                        let new_perm = NewPermission::from_unique_ty(
-                            place.layout.ty,
-                            self.kind,
-                            self.ecx,
-                            /* zero_size */ true,
-                        );
-                        self.retag_ptr_inplace(&place, new_perm)?;
-                    }
                     _ => {
                         // Not a reference/pointer/box. Only recurse if configured appropriately.
                         let recurse = match self.retag_fields {
@@ -533,8 +515,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Retag it. With protection! That is the entire point.
         let new_perm = NewPermission {
             initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true),
-            zero_size: false,
             protector: Some(ProtectorKind::StrongProtector),
+            initial_read: true,
         };
         this.tb_retag_place(place, new_perm)
     }
@@ -594,27 +576,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         tree_borrows.give_pointer_debug_name(tag, nth_parent, name)
     }
 }
-
-/// Takes a place for a `Unique` and turns it into a place with the inner raw pointer.
-/// I.e. input is what you get from the visitor upon encountering an `adt` that is `Unique`,
-/// and output can be used by `retag_ptr_inplace`.
-fn inner_ptr_of_unique<'tcx>(
-    ecx: &MiriInterpCx<'tcx>,
-    place: &PlaceTy<'tcx>,
-) -> InterpResult<'tcx, PlaceTy<'tcx>> {
-    // Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in
-    // `rustc_const_eval`, just with one fewer layer.
-    // Here we have a `Unique(NonNull(*mut), PhantomData)`
-    assert_eq!(place.layout.fields.count(), 2, "Unique must have exactly 2 fields");
-    let (nonnull, phantom) = (ecx.project_field(place, 0)?, ecx.project_field(place, 1)?);
-    assert!(
-        phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
-        "2nd field of `Unique` should be `PhantomData` but is `{:?}`",
-        phantom.layout.ty,
-    );
-    // Now down to `NonNull(*mut)`
-    assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field");
-    let ptr = ecx.project_field(&nonnull, 0)?;
-    // Finally a plain `*mut`
-    interp_ok(ptr)
-}
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 5c12ce39d10..087f6fc3f24 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -8,6 +8,10 @@ use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
 /// The activation states of a pointer.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 enum PermissionPriv {
+    /// represents: a shared reference to interior mutable data.
+    /// allows: all foreign and child accesses;
+    /// rejects: nothing
+    Cell,
     /// represents: a local mutable reference that has not yet been written to;
     /// allows: child reads, foreign reads;
     /// affected by: child writes (becomes Active),
@@ -60,6 +64,14 @@ impl PartialOrd for PermissionPriv {
         use Ordering::*;
         Some(match (self, other) {
             (a, b) if a == b => Equal,
+            // Versions of `Reserved` with different interior mutability are incomparable with each
+            // other.
+            (ReservedIM, ReservedFrz { .. })
+            | (ReservedFrz { .. }, ReservedIM)
+            // `Cell` is not comparable with any other permission
+            // since it never transitions to any other state and we
+            // can never get to `Cell` from another state.
+            | (Cell, _) | (_, Cell) => return None,
             (Disabled, _) => Greater,
             (_, Disabled) => Less,
             (Frozen, _) => Greater,
@@ -71,9 +83,6 @@ impl PartialOrd for PermissionPriv {
                 // `bool` is ordered such that `false <= true`, so this works as intended.
                 c1.cmp(c2)
             }
-            // Versions of `Reserved` with different interior mutability are incomparable with each
-            // other.
-            (ReservedIM, ReservedFrz { .. }) | (ReservedFrz { .. }, ReservedIM) => return None,
         })
     }
 }
@@ -81,17 +90,22 @@ impl PartialOrd for PermissionPriv {
 impl PermissionPriv {
     /// Check if `self` can be the initial state of a pointer.
     fn is_initial(&self) -> bool {
-        matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM)
+        matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell)
     }
 
     /// Reject `ReservedIM` that cannot exist in the presence of a protector.
     fn compatible_with_protector(&self) -> bool {
-        !matches!(self, ReservedIM)
+        // FIXME(TB-Cell): It is unclear what to do here.
+        // `Cell` will occur with a protector but won't provide the guarantees
+        // of noalias (it will fail the `protected_enforces_noalias` test).
+        !matches!(self, ReservedIM | Cell)
     }
 
     /// See `foreign_access_skipping.rs`. Computes the SIFA of a permission.
     fn strongest_idempotent_foreign_access(&self, prot: bool) -> IdempotentForeignAccess {
         match self {
+            // Cell survives any foreign access
+            Cell => IdempotentForeignAccess::Write,
             // A protected non-conflicted Reserved will become conflicted under a foreign read,
             // and is hence not idempotent under it.
             ReservedFrz { conflicted } if prot && !conflicted => IdempotentForeignAccess::None,
@@ -124,7 +138,7 @@ mod transition {
             Disabled => return None,
             // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
             // accesses, since the data is not being mutated. Hence the `{ .. }`.
-            readable @ (ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable,
+            readable @ (Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable,
         })
     }
 
@@ -132,6 +146,8 @@ mod transition {
     /// is protected; invalidate `Active`.
     fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
         Some(match state {
+            // Cell ignores foreign reads.
+            Cell => Cell,
             // Non-writeable states just ignore foreign reads.
             non_writeable @ (Frozen | Disabled) => non_writeable,
             // Writeable states are more tricky, and depend on whether things are protected.
@@ -167,6 +183,8 @@ mod transition {
     /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
     fn child_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
         Some(match state {
+            // Cell ignores child writes.
+            Cell => Cell,
             // If the `conflicted` flag is set, then there was a foreign read during
             // the function call that is still ongoing (still `protected`),
             // this is UB (`noalias` violation).
@@ -185,6 +203,8 @@ mod transition {
         // types receive a `ReservedFrz` instead of `ReservedIM` when retagged under a protector,
         // so the result of this function does indirectly depend on (past) protector status.
         Some(match state {
+            // Cell ignores foreign writes.
+            Cell => Cell,
             res @ ReservedIM => {
                 // We can never create a `ReservedIM` under a protector, only `ReservedFrz`.
                 assert!(!protected);
@@ -242,6 +262,11 @@ impl Permission {
         self.inner == Frozen
     }
 
+    /// Check if `self` is the shared-reference-to-interior-mutable-data state of a pointer.
+    pub fn is_cell(&self) -> bool {
+        self.inner == Cell
+    }
+
     /// Default initial permission of the root of a new tree at inbounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
     pub fn new_active() -> Self {
@@ -278,11 +303,27 @@ impl Permission {
         Self { inner: Disabled }
     }
 
+    /// Default initial permission of a shared reference to interior mutable data.
+    pub fn new_cell() -> Self {
+        Self { inner: Cell }
+    }
+
     /// Reject `ReservedIM` that cannot exist in the presence of a protector.
     pub fn compatible_with_protector(&self) -> bool {
         self.inner.compatible_with_protector()
     }
 
+    /// What kind of access to perform before releasing the protector.
+    pub fn protector_end_access(&self) -> Option<AccessKind> {
+        match self.inner {
+            // Do not do perform access if it is a `Cell`, as this
+            // can cause data races when using thread-safe data types.
+            Cell => None,
+            Active => Some(AccessKind::Write),
+            _ => Some(AccessKind::Read),
+        }
+    }
+
     /// Apply the transition to the inner PermissionPriv.
     pub fn perform_access(
         kind: AccessKind,
@@ -306,30 +347,32 @@ impl Permission {
     /// remove protected parents.
     pub fn can_be_replaced_by_child(self, child: Self) -> bool {
         match (self.inner, child.inner) {
-            // ReservedIM can be replaced by anything, as it allows all
-            // transitions.
+            // Cell allows all transitions.
+            (Cell, _) => true,
+            // Cell is the most permissive, nothing can be replaced by Cell.
+            // (ReservedIM, Cell) => true,
+            (_, Cell) => false,
+            // ReservedIM can be replaced by anything besides Cell.
+            // ReservedIM allows all transitions, but unlike Cell, a local write
+            // to ReservedIM transitions to Active, while it is a no-op for Cell.
             (ReservedIM, _) => true,
+            (_, ReservedIM) => false,
             // Reserved (as parent, where conflictedness does not matter)
-            // can be replaced by all but ReservedIM,
-            // since ReservedIM alone would survive foreign writes
-            (ReservedFrz { .. }, ReservedIM) => false,
+            // can be replaced by all but ReservedIM and Cell,
+            // since ReservedIM and Cell alone would survive foreign writes
             (ReservedFrz { .. }, _) => true,
+            (_, ReservedFrz { .. }) => false,
             // Active can not be replaced by something surviving
-            // foreign reads and then remaining writable.
-            (Active, ReservedIM) => false,
-            (Active, ReservedFrz { .. }) => false,
+            // foreign reads and then remaining writable (i.e., Reserved*).
             // Replacing a state by itself is always okay, even if the child state is protected.
-            (Active, Active) => true,
             // Active can be replaced by Frozen, since it is not protected.
-            (Active, Frozen) => true,
-            (Active, Disabled) => true,
+            (Active, Active | Frozen | Disabled) => true,
+            (_, Active) => false,
             // Frozen can only be replaced by Disabled (and itself).
-            (Frozen, Frozen) => true,
-            (Frozen, Disabled) => true,
-            (Frozen, _) => false,
+            (Frozen, Frozen | Disabled) => true,
+            (_, Frozen) => false,
             // Disabled can not be replaced by anything else.
             (Disabled, Disabled) => true,
-            (Disabled, _) => false,
         }
     }
 
@@ -383,6 +426,7 @@ pub mod diagnostics {
                 f,
                 "{}",
                 match self {
+                    Cell => "Cell",
                     ReservedFrz { conflicted: false } => "Reserved",
                     ReservedFrz { conflicted: true } => "Reserved (conflicted)",
                     ReservedIM => "Reserved (interior mutable)",
@@ -413,6 +457,7 @@ pub mod diagnostics {
             // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
             // alignment will be incorrect.
             match self.inner {
+                Cell => "Cel ",
                 ReservedFrz { conflicted: false } => "Res ",
                 ReservedFrz { conflicted: true } => "ResC",
                 ReservedIM => "ReIM",
@@ -459,7 +504,7 @@ pub mod diagnostics {
         ///   (Reserved < Active < Frozen < Disabled);
         /// - between `self` and `err` the permission should also be increasing,
         ///   so all permissions inside `err` should be greater than `self.1`;
-        /// - `Active` and `Reserved(conflicted=false)` cannot cause an error
+        /// - `Active`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error
         ///   due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)`
         ///   of either of them;
         /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
@@ -492,13 +537,14 @@ pub mod diagnostics {
                         (ReservedFrz { conflicted: true } | Active | Frozen, Disabled) => false,
                         (ReservedFrz { conflicted: true }, Frozen) => false,
 
-                        // `Active` and `Reserved` have all permissions, so a
+                        // `Active`, `Reserved`, and `Cell` have all permissions, so a
                         // `ChildAccessForbidden(Reserved | Active)` can never exist.
-                        (_, Active) | (_, ReservedFrz { conflicted: false }) =>
+                        (_, Active) | (_, ReservedFrz { conflicted: false }) | (_, Cell) =>
                             unreachable!("this permission cannot cause an error"),
                         // No transition has `Reserved { conflicted: false }` or `ReservedIM`
-                        // as its `.to` unless it's a noop.
-                        (ReservedFrz { conflicted: false } | ReservedIM, _) =>
+                        // as its `.to` unless it's a noop. `Cell` cannot be in its `.to`
+                        // because all child accesses are a noop.
+                        (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) =>
                             unreachable!("self is a noop transition"),
                         // All transitions produced in normal executions (using `apply_access`)
                         // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
@@ -544,16 +590,17 @@ pub mod diagnostics {
                                 "permission that results in Disabled should not itself be Disabled in the first place"
                             ),
                         // No transition has `Reserved { conflicted: false }` or `ReservedIM` as its `.to`
-                        // unless it's a noop.
-                        (ReservedFrz { conflicted: false } | ReservedIM, _) =>
+                        // unless it's a noop. `Cell` cannot be in its `.to` because all child
+                        // accesses are a noop.
+                        (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) =>
                             unreachable!("self is a noop transition"),
 
                         // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
                         // so permissions found must be increasing in the order
                         // `self.from < self.to <= forbidden.from < forbidden.to`.
-                        (Disabled, ReservedFrz { .. } | ReservedIM | Active | Frozen)
-                        | (Frozen, ReservedFrz { .. } | ReservedIM | Active)
-                        | (Active, ReservedFrz { .. } | ReservedIM) =>
+                        (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen)
+                        | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Active)
+                        | (Active, Cell | ReservedFrz { .. } | ReservedIM) =>
                             unreachable!("permissions between self and err must be increasing"),
                     }
                 }
@@ -590,7 +637,7 @@ mod propagation_optimization_checks {
     impl Exhaustive for PermissionPriv {
         fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
             Box::new(
-                vec![Active, Frozen, Disabled, ReservedIM]
+                vec![Active, Frozen, Disabled, ReservedIM, Cell]
                     .into_iter()
                     .chain(<bool>::exhaustive().map(|conflicted| ReservedFrz { conflicted })),
             )
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index 3389b1c602c..47ccaadbb9e 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -721,9 +721,14 @@ impl<'tcx> Tree {
                     // visit all children, skipping none
                     |_| ContinueTraversal::Recurse,
                     |args: NodeAppArgs<'_>| -> Result<(), TransitionError> {
-                        let NodeAppArgs { node, .. } = args;
+                        let NodeAppArgs { node, perm, .. } = args;
+                        let perm =
+                            perm.get().copied().unwrap_or_else(|| node.default_location_state());
                         if global.borrow().protected_tags.get(&node.tag)
                             == Some(&ProtectorKind::StrongProtector)
+                            // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
+                            // Related to https://github.com/rust-lang/rust/issues/55005.
+                            && !perm.permission().is_cell()
                         {
                             Err(TransitionError::ProtectedDealloc)
                         } else {
@@ -865,10 +870,9 @@ impl<'tcx> Tree {
                 let idx = self.tag_mapping.get(&tag).unwrap();
                 // Only visit initialized permissions
                 if let Some(p) = perms.get(idx)
+                    && let Some(access_kind) = p.permission.protector_end_access()
                     && p.initialized
                 {
-                    let access_kind =
-                        if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read };
                     let access_cause = diagnostics::AccessCause::FnExit(access_kind);
                     TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
                         .traverse_nonchildren(
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 847c6823475..714eb1fba91 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -1,4 +1,4 @@
-//! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks
+//! Implementation of a data-race detector using Lamport Timestamps / Vector clocks
 //! based on the Dynamic Race Detection for C++:
 //! <https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf>
 //! which does not report false-positives when fences are used, and gives better
@@ -54,6 +54,7 @@ use rustc_span::Span;
 
 use super::vector_clock::{VClock, VTimestamp, VectorIdx};
 use super::weak_memory::EvalContextExt as _;
+use crate::concurrency::GlobalDataRaceHandler;
 use crate::diagnostics::RacingOp;
 use crate::*;
 
@@ -259,7 +260,7 @@ enum AccessType {
 /// Per-byte vector clock metadata for data-race detection.
 #[derive(Clone, PartialEq, Eq, Debug)]
 struct MemoryCellClocks {
-    /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need
+    /// The vector clock timestamp and the thread that did the last non-atomic write. We don't need
     /// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective
     /// clock is all-0 except for the thread that did the write.
     write: (VectorIdx, VTimestamp),
@@ -269,7 +270,7 @@ struct MemoryCellClocks {
     /// a deallocation of memory.
     write_type: NaWriteType,
 
-    /// The vector-clock of all non-atomic reads that happened since the last non-atomic write
+    /// The vector clock of all non-atomic reads that happened since the last non-atomic write
     /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to
     /// zero on each write operation.
     read: VClock,
@@ -298,7 +299,7 @@ struct ThreadExtraState {
 }
 
 /// Global data-race detection state, contains the currently
-/// executing thread as well as the vector-clocks associated
+/// executing thread as well as the vector clocks associated
 /// with each of the threads.
 // FIXME: it is probably better to have one large RefCell, than to have so many small ones.
 #[derive(Debug, Clone)]
@@ -335,7 +336,7 @@ pub struct GlobalState {
     /// for use as the index for a new thread.
     /// Elements in this set may still require the vector index to
     /// report data-races, and can only be re-used after all
-    /// active vector-clocks catch up with the threads timestamp.
+    /// active vector clocks catch up with the threads timestamp.
     reuse_candidates: RefCell<FxHashSet<VectorIdx>>,
 
     /// We make SC fences act like RMWs on a global location.
@@ -348,6 +349,9 @@ pub struct GlobalState {
 
     /// Track when an outdated (weak memory) load happens.
     pub track_outdated_loads: bool,
+
+    /// Whether weak memory emulation is enabled
+    pub weak_memory: bool,
 }
 
 impl VisitProvenance for GlobalState {
@@ -680,6 +684,23 @@ impl MemoryCellClocks {
     }
 }
 
+impl GlobalDataRaceHandler {
+    /// Select whether data race checking is disabled. This is solely an
+    /// implementation detail of `allow_data_races_*` and must not be used anywhere else!
+    fn set_ongoing_action_data_race_free(&self, enable: bool) {
+        match self {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Vclocks(data_race) => {
+                let old = data_race.ongoing_action_data_race_free.replace(enable);
+                assert_ne!(old, enable, "cannot nest allow_data_races");
+            }
+            GlobalDataRaceHandler::Genmc(genmc_ctx) => {
+                genmc_ctx.set_ongoing_action_data_race_free(enable);
+            }
+        }
+    }
+}
+
 /// Evaluation context extensions.
 impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
@@ -696,6 +717,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         // This is fine with StackedBorrow and race checks because they don't concern metadata on
         // the *value* (including the associated provenance if this is an AtomicPtr) at this location.
         // Only metadata on the location itself is used.
+
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics
+            let old_val = None;
+            return genmc_ctx.atomic_load(
+                this,
+                place.ptr().addr(),
+                place.layout.size,
+                atomic,
+                old_val,
+            );
+        }
+
         let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?;
         let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || {
             this.validate_atomic_load(place, atomic)
@@ -718,6 +752,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         // This is also a very special exception where we just ignore an error -- if this read
         // was UB e.g. because the memory is uninitialized, we don't want to know!
         let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err();
+        // Inform GenMC about the atomic store.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics
+            genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?;
+            return interp_ok(());
+        }
         this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
         this.validate_atomic_store(dest, atomic)?;
         this.buffered_atomic_write(val, dest, atomic, old_val)
@@ -737,6 +777,21 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
 
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
 
+        // Inform GenMC about the atomic rmw operation.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics
+            let (old_val, new_val) = genmc_ctx.atomic_rmw_op(
+                this,
+                place.ptr().addr(),
+                place.layout.size,
+                atomic,
+                (op, not),
+                rhs.to_scalar(),
+            )?;
+            this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?;
+            return interp_ok(ImmTy::from_scalar(old_val, old.layout));
+        }
+
         let val = this.binary_op(op, &old, rhs)?;
         let val = if not { this.unary_op(mir::UnOp::Not, &val)? } else { val };
         this.allow_data_races_mut(|this| this.write_immediate(*val, place))?;
@@ -761,6 +816,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         let old = this.allow_data_races_mut(|this| this.read_scalar(place))?;
         this.allow_data_races_mut(|this| this.write_scalar(new, place))?;
 
+        // Inform GenMC about the atomic atomic exchange.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics
+            let (old_val, _is_success) = genmc_ctx.atomic_exchange(
+                this,
+                place.ptr().addr(),
+                place.layout.size,
+                new,
+                atomic,
+            )?;
+            return interp_ok(old_val);
+        }
+
         this.validate_atomic_rmw(place, atomic)?;
 
         this.buffered_atomic_rmw(new, place, atomic, old)?;
@@ -780,6 +848,23 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         this.atomic_access_check(place, AtomicAccessType::Rmw)?;
 
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
+
+        // Inform GenMC about the atomic min/max operation.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics
+            let (old_val, new_val) = genmc_ctx.atomic_min_max_op(
+                this,
+                place.ptr().addr(),
+                place.layout.size,
+                atomic,
+                min,
+                old.layout.backend_repr.is_signed(),
+                rhs.to_scalar(),
+            )?;
+            this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?;
+            return interp_ok(ImmTy::from_scalar(old_val, old.layout));
+        }
+
         let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
 
         #[rustfmt::skip] // rustfmt makes this unreadable
@@ -823,6 +908,25 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
         // read ordering and write in the success case.
         // Read as immediate for the sake of `binary_op()`
         let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
+
+        // Inform GenMC about the atomic atomic compare exchange.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange(
+                this,
+                place.ptr().addr(),
+                place.layout.size,
+                this.read_scalar(expect_old)?,
+                new,
+                success,
+                fail,
+                can_fail_spuriously,
+            )?;
+            if cmpxchg_success {
+                this.allow_data_races_mut(|this| this.write_scalar(new, place))?;
+            }
+            return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success)));
+        }
+
         // `binary_op` will bail if either of them is not a scalar.
         let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?;
         // If the operation would succeed, but is "weak", fail some portion
@@ -859,49 +963,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
     /// Update the data-race detector for an atomic fence on the current thread.
     fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let current_span = this.machine.current_span();
-        if let Some(data_race) = &mut this.machine.data_race {
-            data_race.maybe_perform_sync_operation(
-                &this.machine.threads,
-                current_span,
-                |index, mut clocks| {
-                    trace!("Atomic fence on {:?} with ordering {:?}", index, atomic);
-
-                    // Apply data-race detection for the current fences
-                    // this treats AcqRel and SeqCst as the same as an acquire
-                    // and release fence applied in the same timestamp.
-                    if atomic != AtomicFenceOrd::Release {
-                        // Either Acquire | AcqRel | SeqCst
-                        clocks.apply_acquire_fence();
-                    }
-                    if atomic == AtomicFenceOrd::SeqCst {
-                        // Behave like an RMW on the global fence location. This takes full care of
-                        // all the SC fence requirements, including C++17 §32.4 [atomics.order]
-                        // paragraph 6 (which would limit what future reads can see). It also rules
-                        // out many legal behaviors, but we don't currently have a model that would
-                        // be more precise.
-                        // Also see the second bullet on page 10 of
-                        // <https://www.cs.tau.ac.il/~orilahav/papers/popl21_robustness.pdf>.
-                        let mut sc_fence_clock = data_race.last_sc_fence.borrow_mut();
-                        sc_fence_clock.join(&clocks.clock);
-                        clocks.clock.join(&sc_fence_clock);
-                        // Also establish some sort of order with the last SC write that happened, globally
-                        // (but this is only respected by future reads).
-                        clocks.write_seqcst.join(&data_race.last_sc_write_per_thread.borrow());
-                    }
-                    // The release fence is last, since both of the above could alter our clock,
-                    // which should be part of what is being released.
-                    if atomic != AtomicFenceOrd::Acquire {
-                        // Either Release | AcqRel | SeqCst
-                        clocks.apply_release_fence();
-                    }
-
-                    // Increment timestamp in case of release semantics.
-                    interp_ok(atomic != AtomicFenceOrd::Acquire)
-                },
-            )
-        } else {
-            interp_ok(())
+        let machine = &this.machine;
+        match &this.machine.data_race {
+            GlobalDataRaceHandler::None => interp_ok(()),
+            GlobalDataRaceHandler::Vclocks(data_race) => data_race.atomic_fence(machine, atomic),
+            GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.atomic_fence(machine, atomic),
         }
     }
 
@@ -910,10 +976,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
     fn allow_data_races_all_threads_done(&mut self) {
         let this = self.eval_context_ref();
         assert!(this.have_all_terminated());
-        if let Some(data_race) = &this.machine.data_race {
-            let old = data_race.ongoing_action_data_race_free.replace(true);
-            assert!(!old, "cannot nest allow_data_races");
-        }
+        this.machine.data_race.set_ongoing_action_data_race_free(true);
     }
 
     /// Calls the callback with the "release" clock of the current thread.
@@ -923,14 +986,16 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
     /// The closure will only be invoked if data race handling is on.
     fn release_clock<R>(&self, callback: impl FnOnce(&VClock) -> R) -> Option<R> {
         let this = self.eval_context_ref();
-        Some(this.machine.data_race.as_ref()?.release_clock(&this.machine.threads, callback))
+        Some(
+            this.machine.data_race.as_vclocks_ref()?.release_clock(&this.machine.threads, callback),
+        )
     }
 
     /// Acquire the given clock into the current thread, establishing synchronization with
     /// the moment when that clock snapshot was taken via `release_clock`.
     fn acquire_clock(&self, clock: &VClock) {
         let this = self.eval_context_ref();
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.acquire_clock(clock, &this.machine.threads);
         }
     }
@@ -1132,7 +1197,7 @@ impl VClockAlloc {
         machine: &MiriMachine<'_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
-        let global = machine.data_race.as_ref().unwrap();
+        let global = machine.data_race.as_vclocks_ref().unwrap();
         if !global.race_detecting() {
             return interp_ok(());
         }
@@ -1174,7 +1239,7 @@ impl VClockAlloc {
         machine: &mut MiriMachine<'_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
-        let global = machine.data_race.as_mut().unwrap();
+        let global = machine.data_race.as_vclocks_mut().unwrap();
         if !global.race_detecting() {
             return interp_ok(());
         }
@@ -1228,7 +1293,7 @@ impl Default for LocalClocks {
 impl FrameState {
     pub fn local_write(&self, local: mir::Local, storage_live: bool, machine: &MiriMachine<'_>) {
         let current_span = machine.current_span();
-        let global = machine.data_race.as_ref().unwrap();
+        let global = machine.data_race.as_vclocks_ref().unwrap();
         if !global.race_detecting() {
             return;
         }
@@ -1258,7 +1323,7 @@ impl FrameState {
 
     pub fn local_read(&self, local: mir::Local, machine: &MiriMachine<'_>) {
         let current_span = machine.current_span();
-        let global = machine.data_race.as_ref().unwrap();
+        let global = machine.data_race.as_vclocks_ref().unwrap();
         if !global.race_detecting() {
             return;
         }
@@ -1281,7 +1346,7 @@ impl FrameState {
         alloc: &mut VClockAlloc,
         machine: &MiriMachine<'_>,
     ) {
-        let global = machine.data_race.as_ref().unwrap();
+        let global = machine.data_race.as_vclocks_ref().unwrap();
         if !global.race_detecting() {
             return;
         }
@@ -1314,14 +1379,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     #[inline]
     fn allow_data_races_ref<R>(&self, op: impl FnOnce(&MiriInterpCx<'tcx>) -> R) -> R {
         let this = self.eval_context_ref();
-        if let Some(data_race) = &this.machine.data_race {
-            let old = data_race.ongoing_action_data_race_free.replace(true);
-            assert!(!old, "cannot nest allow_data_races");
-        }
+        this.machine.data_race.set_ongoing_action_data_race_free(true);
         let result = op(this);
-        if let Some(data_race) = &this.machine.data_race {
-            data_race.ongoing_action_data_race_free.set(false);
-        }
+        this.machine.data_race.set_ongoing_action_data_race_free(false);
         result
     }
 
@@ -1331,14 +1391,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     #[inline]
     fn allow_data_races_mut<R>(&mut self, op: impl FnOnce(&mut MiriInterpCx<'tcx>) -> R) -> R {
         let this = self.eval_context_mut();
-        if let Some(data_race) = &this.machine.data_race {
-            let old = data_race.ongoing_action_data_race_free.replace(true);
-            assert!(!old, "cannot nest allow_data_races");
-        }
+        this.machine.data_race.set_ongoing_action_data_race_free(true);
         let result = op(this);
-        if let Some(data_race) = &this.machine.data_race {
-            data_race.ongoing_action_data_race_free.set(false);
-        }
+        this.machine.data_race.set_ongoing_action_data_race_free(false);
         result
     }
 
@@ -1355,7 +1410,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let align = Align::from_bytes(place.layout.size.bytes()).unwrap();
         this.check_ptr_align(place.ptr(), align)?;
         // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable
-        // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and
+        // memory on many targets (i.e., they segfault if that memory is mapped read-only), and
         // atomic loads can be implemented via compare_exchange on some targets. There could
         // possibly be some very specific exceptions to this, see
         // <https://github.com/rust-lang/miri/pull/2464#discussion_r939636130> for details.
@@ -1486,7 +1541,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_ref();
         assert!(access.is_atomic());
-        let Some(data_race) = &this.machine.data_race else { return interp_ok(()) };
+        let Some(data_race) = this.machine.data_race.as_vclocks_ref() else {
+            return interp_ok(());
+        };
         if !data_race.race_detecting() {
             return interp_ok(());
         }
@@ -1494,7 +1551,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?;
         // Load and log the atomic operation.
         // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option.
-        let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap();
+        let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_vclocks_ref().unwrap();
         trace!(
             "Atomic op({}) with ordering {:?} on {:?} (size={})",
             access.description(None, None),
@@ -1565,6 +1622,7 @@ impl GlobalState {
             last_sc_fence: RefCell::new(VClock::default()),
             last_sc_write_per_thread: RefCell::new(VClock::default()),
             track_outdated_loads: config.track_outdated_loads,
+            weak_memory: config.weak_memory_emulation,
         };
 
         // Setup the main-thread since it is not explicitly created:
@@ -1728,7 +1786,7 @@ impl GlobalState {
         }
     }
 
-    /// On thread termination, the vector-clock may re-used
+    /// On thread termination, the vector clock may be re-used
     /// in the future once all remaining thread-clocks catch
     /// up with the time index of the terminated thread.
     /// This assigns thread termination with a unique index
@@ -1750,6 +1808,50 @@ impl GlobalState {
         reuse.insert(current_index);
     }
 
+    /// Update the data-race detector for an atomic fence on the current thread.
+    fn atomic_fence<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        atomic: AtomicFenceOrd,
+    ) -> InterpResult<'tcx> {
+        let current_span = machine.current_span();
+        self.maybe_perform_sync_operation(&machine.threads, current_span, |index, mut clocks| {
+            trace!("Atomic fence on {:?} with ordering {:?}", index, atomic);
+
+            // Apply data-race detection for the current fences
+            // this treats AcqRel and SeqCst as the same as an acquire
+            // and release fence applied in the same timestamp.
+            if atomic != AtomicFenceOrd::Release {
+                // Either Acquire | AcqRel | SeqCst
+                clocks.apply_acquire_fence();
+            }
+            if atomic == AtomicFenceOrd::SeqCst {
+                // Behave like an RMW on the global fence location. This takes full care of
+                // all the SC fence requirements, including C++17 §32.4 [atomics.order]
+                // paragraph 6 (which would limit what future reads can see). It also rules
+                // out many legal behaviors, but we don't currently have a model that would
+                // be more precise.
+                // Also see the second bullet on page 10 of
+                // <https://www.cs.tau.ac.il/~orilahav/papers/popl21_robustness.pdf>.
+                let mut sc_fence_clock = self.last_sc_fence.borrow_mut();
+                sc_fence_clock.join(&clocks.clock);
+                clocks.clock.join(&sc_fence_clock);
+                // Also establish some sort of order with the last SC write that happened, globally
+                // (but this is only respected by future reads).
+                clocks.write_seqcst.join(&self.last_sc_write_per_thread.borrow());
+            }
+            // The release fence is last, since both of the above could alter our clock,
+            // which should be part of what is being released.
+            if atomic != AtomicFenceOrd::Acquire {
+                // Either Release | AcqRel | SeqCst
+                clocks.apply_release_fence();
+            }
+
+            // Increment timestamp in case of release semantics.
+            interp_ok(atomic != AtomicFenceOrd::Acquire)
+        })
+    }
+
     /// Attempt to perform a synchronized operation, this
     /// will perform no operation if multi-threading is
     /// not currently enabled.
diff --git a/src/tools/miri/src/concurrency/data_race_handler.rs b/src/tools/miri/src/concurrency/data_race_handler.rs
new file mode 100644
index 00000000000..047c37e56b8
--- /dev/null
+++ b/src/tools/miri/src/concurrency/data_race_handler.rs
@@ -0,0 +1,91 @@
+use std::rc::Rc;
+
+use super::{data_race, weak_memory};
+use crate::concurrency::GenmcCtx;
+use crate::{VisitProvenance, VisitWith};
+
+pub enum GlobalDataRaceHandler {
+    /// No data race detection will be done.
+    None,
+    /// State required to run in GenMC mode.
+    /// In this mode, the program will be executed repeatedly to explore different concurrent executions.
+    /// The `GenmcCtx` must persist across multiple executions, so it is behind an `Rc`.
+    ///
+    /// The `GenmcCtx` has several methods with which to inform it about events like atomic memory accesses.
+    /// In GenMC mode, some functionality is taken over by GenMC:
+    /// - Memory Allocation:    Allocated addresses need to be consistent across executions, which Miri's allocator doesn't guarantee
+    /// - Scheduling:           To influence which concurrent execution we will explore next, GenMC takes over scheduling
+    /// - Atomic operations:    GenMC will ensure that we explore all possible values that the memory model allows
+    ///   an atomic operation to see at any specific point of the program.
+    Genmc(Rc<GenmcCtx>),
+    /// The default data race detector for Miri using vector clocks.
+    Vclocks(Box<data_race::GlobalState>),
+}
+
+#[derive(Debug)]
+pub enum AllocDataRaceHandler {
+    None,
+    Genmc,
+    /// Data race detection via the use of vector clocks.
+    /// Weak memory emulation via the use of store buffers (if enabled).
+    Vclocks(data_race::AllocState, Option<weak_memory::AllocState>),
+}
+
+impl GlobalDataRaceHandler {
+    pub fn is_none(&self) -> bool {
+        matches!(self, GlobalDataRaceHandler::None)
+    }
+
+    pub fn as_vclocks_ref(&self) -> Option<&data_race::GlobalState> {
+        if let Self::Vclocks(data_race) = self { Some(data_race) } else { None }
+    }
+
+    pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::GlobalState> {
+        if let Self::Vclocks(data_race) = self { Some(data_race) } else { None }
+    }
+
+    pub fn as_genmc_ref(&self) -> Option<&GenmcCtx> {
+        if let Self::Genmc(genmc_ctx) = self { Some(genmc_ctx) } else { None }
+    }
+}
+
+impl AllocDataRaceHandler {
+    pub fn as_vclocks_ref(&self) -> Option<&data_race::AllocState> {
+        if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None }
+    }
+
+    pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::AllocState> {
+        if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None }
+    }
+
+    pub fn as_weak_memory_ref(&self) -> Option<&weak_memory::AllocState> {
+        if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_ref() } else { None }
+    }
+
+    pub fn as_weak_memory_mut(&mut self) -> Option<&mut weak_memory::AllocState> {
+        if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_mut() } else { None }
+    }
+}
+
+impl VisitProvenance for GlobalDataRaceHandler {
+    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
+        match self {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Vclocks(data_race) => data_race.visit_provenance(visit),
+            GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.visit_provenance(visit),
+        }
+    }
+}
+
+impl VisitProvenance for AllocDataRaceHandler {
+    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
+        match self {
+            AllocDataRaceHandler::None => {}
+            AllocDataRaceHandler::Genmc => {}
+            AllocDataRaceHandler::Vclocks(data_race, weak_memory) => {
+                data_race.visit_provenance(visit);
+                weak_memory.visit_provenance(visit);
+            }
+        }
+    }
+}
diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs
new file mode 100644
index 00000000000..f91211a670f
--- /dev/null
+++ b/src/tools/miri/src/concurrency/genmc/config.rs
@@ -0,0 +1,19 @@
+use crate::MiriConfig;
+
+#[derive(Debug, Default, Clone)]
+pub struct GenmcConfig {
+    // TODO: add fields
+}
+
+impl GenmcConfig {
+    /// Function for parsing command line options for GenMC mode.
+    /// All GenMC arguments start with the string "-Zmiri-genmc".
+    ///
+    /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed
+    pub fn parse_arg(genmc_config: &mut Option<GenmcConfig>, trimmed_arg: &str) {
+        if genmc_config.is_none() {
+            *genmc_config = Some(Default::default());
+        }
+        todo!("implement parsing of GenMC options")
+    }
+}
diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs
new file mode 100644
index 00000000000..3d0558fb685
--- /dev/null
+++ b/src/tools/miri/src/concurrency/genmc/dummy.rs
@@ -0,0 +1,239 @@
+#![allow(unused)]
+
+use rustc_abi::{Align, Size};
+use rustc_const_eval::interpret::{InterpCx, InterpResult};
+use rustc_middle::mir;
+
+use crate::{
+    AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig,
+    MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith,
+};
+
+#[derive(Debug)]
+pub struct GenmcCtx {}
+
+#[derive(Debug, Default, Clone)]
+pub struct GenmcConfig {}
+
+impl GenmcCtx {
+    pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self {
+        unreachable!()
+    }
+
+    pub fn get_stuck_execution_count(&self) -> usize {
+        unreachable!()
+    }
+
+    pub fn print_genmc_graph(&self) {
+        unreachable!()
+    }
+
+    pub fn is_exploration_done(&self) -> bool {
+        unreachable!()
+    }
+
+    /**** Memory access handling ****/
+
+    pub(crate) fn handle_execution_start(&self) {
+        unreachable!()
+    }
+
+    pub(crate) fn handle_execution_end<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+    ) -> Result<(), String> {
+        unreachable!()
+    }
+
+    pub(super) fn set_ongoing_action_data_race_free(&self, _enable: bool) {
+        unreachable!()
+    }
+
+    //* might fails if there's a race, load might also not read anything (returns None) */
+    pub(crate) fn atomic_load<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        _address: Size,
+        _size: Size,
+        _ordering: AtomicReadOrd,
+        _old_val: Option<Scalar>,
+    ) -> InterpResult<'tcx, Scalar> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_store<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        _address: Size,
+        _size: Size,
+        _value: Scalar,
+        _ordering: AtomicWriteOrd,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_fence<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _ordering: AtomicFenceOrd,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_rmw_op<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        _address: Size,
+        _size: Size,
+        _ordering: AtomicRwOrd,
+        (rmw_op, not): (mir::BinOp, bool),
+        _rhs_scalar: Scalar,
+    ) -> InterpResult<'tcx, (Scalar, Scalar)> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_min_max_op<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        ordering: AtomicRwOrd,
+        min: bool,
+        is_signed: bool,
+        rhs_scalar: Scalar,
+    ) -> InterpResult<'tcx, (Scalar, Scalar)> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_exchange<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        _address: Size,
+        _size: Size,
+        _rhs_scalar: Scalar,
+        _ordering: AtomicRwOrd,
+    ) -> InterpResult<'tcx, (Scalar, bool)> {
+        unreachable!()
+    }
+
+    pub(crate) fn atomic_compare_exchange<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        _address: Size,
+        _size: Size,
+        _expected_old_value: Scalar,
+        _new_value: Scalar,
+        _success: AtomicRwOrd,
+        _fail: AtomicReadOrd,
+        _can_fail_spuriously: bool,
+    ) -> InterpResult<'tcx, (Scalar, bool)> {
+        unreachable!()
+    }
+
+    pub(crate) fn memory_load<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _address: Size,
+        _size: Size,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    pub(crate) fn memory_store<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _address: Size,
+        _size: Size,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    /**** Memory (de)allocation ****/
+
+    pub(crate) fn handle_alloc<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _size: Size,
+        _alignment: Align,
+        _memory_kind: MemoryKind,
+    ) -> InterpResult<'tcx, u64> {
+        unreachable!()
+    }
+
+    pub(crate) fn handle_dealloc<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _address: Size,
+        _size: Size,
+        _align: Align,
+        _kind: MemoryKind,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    /**** Thread management ****/
+
+    pub(crate) fn handle_thread_create<'tcx>(
+        &self,
+        _threads: &ThreadManager<'tcx>,
+        _new_thread_id: ThreadId,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    pub(crate) fn handle_thread_join<'tcx>(
+        &self,
+        _active_thread_id: ThreadId,
+        _child_thread_id: ThreadId,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) {
+        unreachable!()
+    }
+
+    pub(crate) fn handle_thread_finish<'tcx>(
+        &self,
+        _threads: &ThreadManager<'tcx>,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+
+    /**** Scheduling functionality ****/
+
+    pub(crate) fn schedule_thread<'tcx>(
+        &self,
+        _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+    ) -> InterpResult<'tcx, ThreadId> {
+        unreachable!()
+    }
+
+    /**** Blocking instructions ****/
+
+    pub(crate) fn handle_verifier_assume<'tcx>(
+        &self,
+        _machine: &MiriMachine<'tcx>,
+        _condition: bool,
+    ) -> InterpResult<'tcx, ()> {
+        unreachable!()
+    }
+}
+
+impl VisitProvenance for GenmcCtx {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        unreachable!()
+    }
+}
+
+impl GenmcConfig {
+    pub fn parse_arg(_genmc_config: &mut Option<GenmcConfig>, trimmed_arg: &str) {
+        unimplemented!(
+            "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\""
+        );
+    }
+
+    pub fn should_print_graph(&self, _rep: usize) -> bool {
+        unreachable!()
+    }
+}
diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs
new file mode 100644
index 00000000000..0dfd4b9b80f
--- /dev/null
+++ b/src/tools/miri/src/concurrency/genmc/mod.rs
@@ -0,0 +1,284 @@
+#![allow(unused)] // FIXME(GenMC): remove this
+
+use std::cell::Cell;
+
+use rustc_abi::{Align, Size};
+use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok};
+use rustc_middle::mir;
+
+use crate::{
+    AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig,
+    MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith,
+};
+
+mod config;
+
+pub use self::config::GenmcConfig;
+
+// FIXME(GenMC): add fields
+pub struct GenmcCtx {
+    /// Some actions Miri does are allowed to cause data races.
+    /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set.
+    allow_data_races: Cell<bool>,
+}
+
+impl GenmcCtx {
+    /// Create a new `GenmcCtx` from a given config.
+    pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self {
+        assert!(miri_config.genmc_mode);
+        todo!()
+    }
+
+    pub fn get_stuck_execution_count(&self) -> usize {
+        todo!()
+    }
+
+    pub fn print_genmc_graph(&self) {
+        todo!()
+    }
+
+    /// This function determines if we should continue exploring executions or if we are done.
+    ///
+    /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found.
+    pub fn is_exploration_done(&self) -> bool {
+        todo!()
+    }
+
+    /// Inform GenMC that a new program execution has started.
+    /// This function should be called at the start of every execution.
+    pub(crate) fn handle_execution_start(&self) {
+        todo!()
+    }
+
+    /// Inform GenMC that the program's execution has ended.
+    ///
+    /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`).
+    pub(crate) fn handle_execution_end<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+    ) -> Result<(), String> {
+        todo!()
+    }
+
+    /**** Memory access handling ****/
+
+    /// Select whether data race free actions should be allowed. This function should be used carefully!
+    ///
+    /// If `true` is passed, allow for data races to happen without triggering an error, until this function is called again with argument `false`.
+    /// This allows for racy non-atomic memory accesses to be ignored (GenMC is not informed about them at all).
+    ///
+    /// Certain operations are not permitted in GenMC mode with data races disabled and will cause a panic, e.g., atomic accesses or asking for scheduling decisions.
+    ///
+    /// # Panics
+    /// If data race free is attempted to be set more than once (i.e., no nesting allowed).
+    pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) {
+        let old = self.allow_data_races.replace(enable);
+        assert_ne!(old, enable, "cannot nest allow_data_races");
+    }
+
+    pub(crate) fn atomic_load<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        ordering: AtomicReadOrd,
+        old_val: Option<Scalar>,
+    ) -> InterpResult<'tcx, Scalar> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn atomic_store<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        value: Scalar,
+        ordering: AtomicWriteOrd,
+    ) -> InterpResult<'tcx, ()> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn atomic_fence<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        ordering: AtomicFenceOrd,
+    ) -> InterpResult<'tcx, ()> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    /// Inform GenMC about an atomic read-modify-write operation.
+    ///
+    /// Returns `(old_val, new_val)`.
+    pub(crate) fn atomic_rmw_op<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        ordering: AtomicRwOrd,
+        (rmw_op, not): (mir::BinOp, bool),
+        rhs_scalar: Scalar,
+    ) -> InterpResult<'tcx, (Scalar, Scalar)> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    /// Inform GenMC about an atomic `min` or `max` operation.
+    ///
+    /// Returns `(old_val, new_val)`.
+    pub(crate) fn atomic_min_max_op<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        ordering: AtomicRwOrd,
+        min: bool,
+        is_signed: bool,
+        rhs_scalar: Scalar,
+    ) -> InterpResult<'tcx, (Scalar, Scalar)> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn atomic_exchange<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        rhs_scalar: Scalar,
+        ordering: AtomicRwOrd,
+    ) -> InterpResult<'tcx, (Scalar, bool)> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn atomic_compare_exchange<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+        address: Size,
+        size: Size,
+        expected_old_value: Scalar,
+        new_value: Scalar,
+        success: AtomicRwOrd,
+        fail: AtomicReadOrd,
+        can_fail_spuriously: bool,
+    ) -> InterpResult<'tcx, (Scalar, bool)> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    /// Inform GenMC about a non-atomic memory load
+    ///
+    /// NOTE: Unlike for *atomic* loads, we don't return a value here. Non-atomic values are still handled by Miri.
+    pub(crate) fn memory_load<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        address: Size,
+        size: Size,
+    ) -> InterpResult<'tcx, ()> {
+        todo!()
+    }
+
+    pub(crate) fn memory_store<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        address: Size,
+        size: Size,
+    ) -> InterpResult<'tcx, ()> {
+        todo!()
+    }
+
+    /**** Memory (de)allocation ****/
+
+    pub(crate) fn handle_alloc<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        size: Size,
+        alignment: Align,
+        memory_kind: MemoryKind,
+    ) -> InterpResult<'tcx, u64> {
+        todo!()
+    }
+
+    pub(crate) fn handle_dealloc<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        address: Size,
+        size: Size,
+        align: Align,
+        kind: MemoryKind,
+    ) -> InterpResult<'tcx, ()> {
+        todo!()
+    }
+
+    /**** Thread management ****/
+
+    pub(crate) fn handle_thread_create<'tcx>(
+        &self,
+        threads: &ThreadManager<'tcx>,
+        new_thread_id: ThreadId,
+    ) -> InterpResult<'tcx, ()> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn handle_thread_join<'tcx>(
+        &self,
+        active_thread_id: ThreadId,
+        child_thread_id: ThreadId,
+    ) -> InterpResult<'tcx, ()> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) {
+        todo!()
+    }
+
+    pub(crate) fn handle_thread_finish<'tcx>(
+        &self,
+        threads: &ThreadManager<'tcx>,
+    ) -> InterpResult<'tcx, ()> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    /**** Scheduling functionality ****/
+
+    /// Ask for a scheduling decision. This should be called before every MIR instruction.
+    ///
+    /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`).
+    ///
+    /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors.
+    pub(crate) fn schedule_thread<'tcx>(
+        &self,
+        ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
+    ) -> InterpResult<'tcx, ThreadId> {
+        assert!(!self.allow_data_races.get());
+        todo!()
+    }
+
+    /**** Blocking instructions ****/
+
+    pub(crate) fn handle_verifier_assume<'tcx>(
+        &self,
+        machine: &MiriMachine<'tcx>,
+        condition: bool,
+    ) -> InterpResult<'tcx, ()> {
+        if condition { interp_ok(()) } else { self.handle_user_block(machine) }
+    }
+}
+
+impl VisitProvenance for GenmcCtx {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // We don't have any tags.
+    }
+}
+
+impl GenmcCtx {
+    fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> {
+        todo!()
+    }
+}
diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs
index 534f02545bd..c26384f65f6 100644
--- a/src/tools/miri/src/concurrency/init_once.rs
+++ b/src/tools/miri/src/concurrency/init_once.rs
@@ -72,7 +72,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         init_once.status = InitOnceStatus::Complete;
 
         // Each complete happens-before the end of the wait
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race
                 .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock));
         }
@@ -99,7 +99,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         init_once.status = InitOnceStatus::Uninitialized;
 
         // Each complete happens-before the end of the wait
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race
                 .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock));
         }
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index c5082b4e40b..dd33f90f153 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -1,5 +1,6 @@
 pub mod cpu_affinity;
 pub mod data_race;
+mod data_race_handler;
 pub mod init_once;
 mod range_object_map;
 pub mod sync;
@@ -7,4 +8,19 @@ pub mod thread;
 mod vector_clock;
 pub mod weak_memory;
 
+// Import either the real genmc adapter or a dummy module.
+cfg_match! {
+    feature = "genmc" => {
+        mod genmc;
+        pub use self::genmc::{GenmcCtx, GenmcConfig};
+    }
+    _ => {
+        #[path = "genmc/dummy.rs"]
+        mod genmc_dummy;
+        use self::genmc_dummy as genmc;
+        pub use self::genmc::{GenmcCtx, GenmcConfig};
+    }
+}
+
+pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler};
 pub use self::vector_clock::VClock;
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 268268848ed..64f34d3e21c 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -361,7 +361,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             mutex.owner = Some(thread);
         }
         mutex.lock_count = mutex.lock_count.strict_add(1);
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.acquire_clock(&mutex.clock, &this.machine.threads);
         }
     }
@@ -385,7 +385,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 mutex.owner = None;
                 // The mutex is completely unlocked. Try transferring ownership
                 // to another thread.
-                if let Some(data_race) = &this.machine.data_race {
+
+                if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
                     data_race.release_clock(&this.machine.threads, |clock| {
                         mutex.clock.clone_from(clock)
                     });
@@ -477,7 +478,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let rwlock = &mut this.machine.sync.rwlocks[id];
         let count = rwlock.readers.entry(thread).or_insert(0);
         *count = count.strict_add(1);
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads);
         }
     }
@@ -502,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock
         }
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             // Add this to the shared-release clock of all concurrent readers.
             data_race.release_clock(&this.machine.threads, |clock| {
                 rwlock.clock_current_readers.join(clock)
@@ -565,7 +566,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         trace!("rwlock_writer_lock: {:?} now held by {:?}", id, thread);
         let rwlock = &mut this.machine.sync.rwlocks[id];
         rwlock.writer = Some(thread);
-        if let Some(data_race) = &this.machine.data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads);
         }
     }
@@ -585,7 +586,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             rwlock.writer = None;
             trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, thread);
             // Record release clock for next lock holder.
-            if let Some(data_race) = &this.machine.data_race {
+            if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
                 data_race.release_clock(&this.machine.threads, |clock| {
                     rwlock.clock_unlocked.clone_from(clock)
                 });
@@ -691,7 +692,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     match unblock {
                         UnblockKind::Ready => {
                             // The condvar was signaled. Make sure we get the clock for that.
-                            if let Some(data_race) = &this.machine.data_race {
+                            if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
                                 data_race.acquire_clock(
                                     &this.machine.sync.condvars[condvar].clock,
                                     &this.machine.threads,
@@ -721,10 +722,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn condvar_signal(&mut self, id: CondvarId) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
         let condvar = &mut this.machine.sync.condvars[id];
-        let data_race = &this.machine.data_race;
 
         // Each condvar signal happens-before the end of the condvar wake
-        if let Some(data_race) = data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.release_clock(&this.machine.threads, |clock| condvar.clock.clone_from(clock));
         }
         let Some(waiter) = condvar.waiters.pop_front() else {
@@ -764,7 +764,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         UnblockKind::Ready => {
                             let futex = futex_ref.0.borrow();
                             // Acquire the clock of the futex.
-                            if let Some(data_race) = &this.machine.data_race {
+                            if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
                                 data_race.acquire_clock(&futex.clock, &this.machine.threads);
                             }
                         },
@@ -792,10 +792,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, usize> {
         let this = self.eval_context_mut();
         let mut futex = futex_ref.0.borrow_mut();
-        let data_race = &this.machine.data_race;
 
         // Each futex-wake happens-before the end of the futex wait
-        if let Some(data_race) = data_race {
+        if let Some(data_race) = this.machine.data_race.as_vclocks_ref() {
             data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock));
         }
 
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 72fa918e8e5..8aa65e6cb61 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -6,6 +6,7 @@ use std::task::Poll;
 use std::time::{Duration, SystemTime};
 
 use either::Either;
+use rand::seq::IteratorRandom;
 use rustc_abi::ExternAbi;
 use rustc_const_eval::CTRL_C_RECEIVED;
 use rustc_data_structures::fx::FxHashMap;
@@ -15,7 +16,7 @@ use rustc_middle::mir::Mutability;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::Span;
 
-use crate::concurrency::data_race;
+use crate::concurrency::GlobalDataRaceHandler;
 use crate::shims::tls;
 use crate::*;
 
@@ -401,6 +402,8 @@ pub struct ThreadManager<'tcx> {
     thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>,
     /// A flag that indicates that we should change the active thread.
     yield_active_thread: bool,
+    /// A flag that indicates that we should do round robin scheduling of threads else randomized scheduling is used.
+    fixed_scheduling: bool,
 }
 
 impl VisitProvenance for ThreadManager<'_> {
@@ -410,6 +413,7 @@ impl VisitProvenance for ThreadManager<'_> {
             thread_local_allocs,
             active_thread: _,
             yield_active_thread: _,
+            fixed_scheduling: _,
         } = self;
 
         for thread in threads {
@@ -421,8 +425,8 @@ impl VisitProvenance for ThreadManager<'_> {
     }
 }
 
-impl<'tcx> Default for ThreadManager<'tcx> {
-    fn default() -> Self {
+impl<'tcx> ThreadManager<'tcx> {
+    pub(crate) fn new(config: &MiriConfig) -> Self {
         let mut threads = IndexVec::new();
         // Create the main thread and add it to the list of threads.
         threads.push(Thread::new(Some("main"), None));
@@ -431,11 +435,10 @@ impl<'tcx> Default for ThreadManager<'tcx> {
             threads,
             thread_local_allocs: Default::default(),
             yield_active_thread: false,
+            fixed_scheduling: config.fixed_scheduling,
         }
     }
-}
 
-impl<'tcx> ThreadManager<'tcx> {
     pub(crate) fn init(
         ecx: &mut MiriInterpCx<'tcx>,
         on_main_stack_empty: StackEmptyCallback<'tcx>,
@@ -580,13 +583,28 @@ impl<'tcx> ThreadManager<'tcx> {
     fn join_thread(
         &mut self,
         joined_thread_id: ThreadId,
-        data_race: Option<&mut data_race::GlobalState>,
+        data_race_handler: &mut GlobalDataRaceHandler,
     ) -> InterpResult<'tcx> {
         if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached {
             // On Windows this corresponds to joining on a closed handle.
             throw_ub_format!("trying to join a detached thread");
         }
 
+        fn after_join<'tcx>(
+            threads: &mut ThreadManager<'_>,
+            joined_thread_id: ThreadId,
+            data_race_handler: &mut GlobalDataRaceHandler,
+        ) -> InterpResult<'tcx> {
+            match data_race_handler {
+                GlobalDataRaceHandler::None => {}
+                GlobalDataRaceHandler::Vclocks(data_race) =>
+                    data_race.thread_joined(threads, joined_thread_id),
+                GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                    genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?,
+            }
+            interp_ok(())
+        }
+
         // Mark the joined thread as being joined so that we detect if other
         // threads try to join it.
         self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined;
@@ -606,18 +624,13 @@ impl<'tcx> ThreadManager<'tcx> {
                     }
                     |this, unblock: UnblockKind| {
                         assert_eq!(unblock, UnblockKind::Ready);
-                        if let Some(data_race) = &mut this.machine.data_race {
-                            data_race.thread_joined(&this.machine.threads, joined_thread_id);
-                        }
-                        interp_ok(())
+                        after_join(&mut this.machine.threads, joined_thread_id, &mut this.machine.data_race)
                     }
                 ),
             );
         } else {
             // The thread has already terminated - establish happens-before
-            if let Some(data_race) = data_race {
-                data_race.thread_joined(self, joined_thread_id);
-            }
+            after_join(self, joined_thread_id, data_race_handler)?;
         }
         interp_ok(())
     }
@@ -627,7 +640,7 @@ impl<'tcx> ThreadManager<'tcx> {
     fn join_thread_exclusive(
         &mut self,
         joined_thread_id: ThreadId,
-        data_race: Option<&mut data_race::GlobalState>,
+        data_race_handler: &mut GlobalDataRaceHandler,
     ) -> InterpResult<'tcx> {
         if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined {
             throw_ub_format!("trying to join an already joined thread");
@@ -645,7 +658,7 @@ impl<'tcx> ThreadManager<'tcx> {
             "this thread already has threads waiting for its termination"
         );
 
-        self.join_thread(joined_thread_id, data_race)
+        self.join_thread(joined_thread_id, data_race_handler)
     }
 
     /// Set the name of the given thread.
@@ -695,70 +708,6 @@ impl<'tcx> ThreadManager<'tcx> {
             })
             .min()
     }
-
-    /// Decide which action to take next and on which thread.
-    ///
-    /// The currently implemented scheduling policy is the one that is commonly
-    /// used in stateless model checkers such as Loom: run the active thread as
-    /// long as we can and switch only when we have to (the active thread was
-    /// blocked, terminated, or has explicitly asked to be preempted).
-    fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> {
-        // This thread and the program can keep going.
-        if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread {
-            // The currently active thread is still enabled, just continue with it.
-            return interp_ok(SchedulingAction::ExecuteStep);
-        }
-        // The active thread yielded or got terminated. Let's see if there are any timeouts to take
-        // care of. We do this *before* running any other thread, to ensure that timeouts "in the
-        // past" fire before any other thread can take an action. This ensures that for
-        // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by
-        // abstime has already been passed at the time of the call".
-        // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
-        let potential_sleep_time = self.next_callback_wait_time(clock);
-        if potential_sleep_time == Some(Duration::ZERO) {
-            return interp_ok(SchedulingAction::ExecuteTimeoutCallback);
-        }
-        // No callbacks immediately scheduled, pick a regular thread to execute.
-        // The active thread blocked or yielded. So we go search for another enabled thread.
-        // Crucially, we start searching at the current active thread ID, rather than at 0, since we
-        // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2.
-        //
-        // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after*
-        // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the
-        // active thread.
-        let threads = self
-            .threads
-            .iter_enumerated()
-            .skip(self.active_thread.index() + 1)
-            .chain(self.threads.iter_enumerated().take(self.active_thread.index()));
-        for (id, thread) in threads {
-            debug_assert_ne!(self.active_thread, id);
-            if thread.state.is_enabled() {
-                info!(
-                    "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------",
-                    self.get_thread_display_name(id),
-                    self.get_thread_display_name(self.active_thread)
-                );
-                self.active_thread = id;
-                break;
-            }
-        }
-        self.yield_active_thread = false;
-        if self.threads[self.active_thread].state.is_enabled() {
-            return interp_ok(SchedulingAction::ExecuteStep);
-        }
-        // We have not found a thread to execute.
-        if self.threads.iter().all(|thread| thread.state.is_terminated()) {
-            unreachable!("all threads terminated without the main thread terminating?!");
-        } else if let Some(sleep_time) = potential_sleep_time {
-            // All threads are currently blocked, but we have unexecuted
-            // timeout_callbacks, which may unblock some of the threads. Hence,
-            // sleep until the first callback.
-            interp_ok(SchedulingAction::Sleep(sleep_time))
-        } else {
-            throw_machine_stop!(TerminationInfo::Deadlock);
-        }
-    }
 }
 
 impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {}
@@ -806,6 +755,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     #[inline]
     fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> {
         let this = self.eval_context_mut();
+        // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling.
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            let thread_id = this.active_thread();
+            genmc_ctx.handle_thread_stack_empty(thread_id);
+        }
         let mut callback = this
             .active_thread_mut()
             .on_stack_empty
@@ -815,6 +769,102 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
         this.active_thread_mut().on_stack_empty = Some(callback);
         interp_ok(res)
     }
+
+    /// Decide which action to take next and on which thread.
+    ///
+    /// The currently implemented scheduling policy is the one that is commonly
+    /// used in stateless model checkers such as Loom: run the active thread as
+    /// long as we can and switch only when we have to (the active thread was
+    /// blocked, terminated, or has explicitly asked to be preempted).
+    ///
+    /// If GenMC mode is active, the scheduling is instead handled by GenMC.
+    fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> {
+        let this = self.eval_context_mut();
+        // In GenMC mode, we let GenMC do the scheduling
+        if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() {
+            let next_thread_id = genmc_ctx.schedule_thread(this)?;
+
+            let thread_manager = &mut this.machine.threads;
+            thread_manager.active_thread = next_thread_id;
+            thread_manager.yield_active_thread = false;
+
+            assert!(thread_manager.threads[thread_manager.active_thread].state.is_enabled());
+            return interp_ok(SchedulingAction::ExecuteStep);
+        }
+
+        // We are not in GenMC mode, so we control the schedule
+        let thread_manager = &mut this.machine.threads;
+        let clock = &this.machine.monotonic_clock;
+        let rng = this.machine.rng.get_mut();
+        // This thread and the program can keep going.
+        if thread_manager.threads[thread_manager.active_thread].state.is_enabled()
+            && !thread_manager.yield_active_thread
+        {
+            // The currently active thread is still enabled, just continue with it.
+            return interp_ok(SchedulingAction::ExecuteStep);
+        }
+        // The active thread yielded or got terminated. Let's see if there are any timeouts to take
+        // care of. We do this *before* running any other thread, to ensure that timeouts "in the
+        // past" fire before any other thread can take an action. This ensures that for
+        // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by
+        // abstime has already been passed at the time of the call".
+        // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
+        let potential_sleep_time = thread_manager.next_callback_wait_time(clock);
+        if potential_sleep_time == Some(Duration::ZERO) {
+            return interp_ok(SchedulingAction::ExecuteTimeoutCallback);
+        }
+        // No callbacks immediately scheduled, pick a regular thread to execute.
+        // The active thread blocked or yielded. So we go search for another enabled thread.
+        // We build the list of threads by starting with the threads after the current one, followed by
+        // the threads before the current one and then the current thread itself (i.e., this iterator acts
+        // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first
+        // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step.
+        let mut threads_iter = thread_manager
+            .threads
+            .iter_enumerated()
+            .skip(thread_manager.active_thread.index() + 1)
+            .chain(
+                thread_manager
+                    .threads
+                    .iter_enumerated()
+                    .take(thread_manager.active_thread.index() + 1),
+            )
+            .filter(|(_id, thread)| thread.state.is_enabled());
+        // Pick a new thread, and switch to it.
+        let new_thread = if thread_manager.fixed_scheduling {
+            threads_iter.next()
+        } else {
+            threads_iter.choose(rng)
+        };
+
+        if let Some((id, _thread)) = new_thread {
+            if thread_manager.active_thread != id {
+                info!(
+                    "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------",
+                    thread_manager.get_thread_display_name(id),
+                    thread_manager.get_thread_display_name(thread_manager.active_thread)
+                );
+                thread_manager.active_thread = id;
+            }
+        }
+        // This completes the `yield`, if any was requested.
+        thread_manager.yield_active_thread = false;
+
+        if thread_manager.threads[thread_manager.active_thread].state.is_enabled() {
+            return interp_ok(SchedulingAction::ExecuteStep);
+        }
+        // We have not found a thread to execute.
+        if thread_manager.threads.iter().all(|thread| thread.state.is_terminated()) {
+            unreachable!("all threads terminated without the main thread terminating?!");
+        } else if let Some(sleep_time) = potential_sleep_time {
+            // All threads are currently blocked, but we have unexecuted
+            // timeout_callbacks, which may unblock some of the threads. Hence,
+            // sleep until the first callback.
+            interp_ok(SchedulingAction::Sleep(sleep_time))
+        } else {
+            throw_machine_stop!(TerminationInfo::Deadlock);
+        }
+    }
 }
 
 // Public interface to thread management.
@@ -880,10 +930,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Box::new(move |m| state.on_stack_empty(m))
         });
         let current_span = this.machine.current_span();
-        if let Some(data_race) = &mut this.machine.data_race {
-            data_race.thread_created(&this.machine.threads, new_thread_id, current_span);
+        match &mut this.machine.data_race {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Vclocks(data_race) =>
+                data_race.thread_created(&this.machine.threads, new_thread_id, current_span),
+            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?,
         }
-
         // Write the current thread-id, switch to the next thread later
         // to treat this write operation as occurring on the current thread.
         if let Some(thread_info_place) = thread {
@@ -930,12 +983,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// This is called by the eval loop when a thread's on_stack_empty returns `Ready`.
     fn terminate_active_thread(&mut self, tls_alloc_action: TlsAllocAction) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
+
         // Mark thread as terminated.
         let thread = this.active_thread_mut();
         assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated");
         thread.state = ThreadState::Terminated;
-        if let Some(ref mut data_race) = this.machine.data_race {
-            data_race.thread_terminated(&this.machine.threads);
+        match &mut this.machine.data_race {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Vclocks(data_race) =>
+                data_race.thread_terminated(&this.machine.threads),
+            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                genmc_ctx.handle_thread_finish(&this.machine.threads)?,
         }
         // Deallocate TLS.
         let gone_thread = this.active_thread();
@@ -1051,7 +1109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     #[inline]
     fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?;
+        this.machine.threads.join_thread(joined_thread_id, &mut this.machine.data_race)?;
         interp_ok(())
     }
 
@@ -1060,7 +1118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         this.machine
             .threads
-            .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?;
+            .join_thread_exclusive(joined_thread_id, &mut this.machine.data_race)?;
         interp_ok(())
     }
 
@@ -1138,7 +1196,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         use rand::Rng as _;
 
         let this = self.eval_context_mut();
-        if this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) {
+        if !this.machine.threads.fixed_scheduling
+            && this.machine.rng.get_mut().random_bool(this.machine.preemption_rate)
+        {
             this.yield_active_thread();
         }
     }
@@ -1152,7 +1212,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.handle_abnormal_termination();
                 throw_machine_stop!(TerminationInfo::Interrupted);
             }
-            match this.machine.threads.schedule(&this.machine.monotonic_clock)? {
+            match this.schedule()? {
                 SchedulingAction::ExecuteStep => {
                     if !this.step()? {
                         // See if this thread can do something else.
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index 34572663429..78858fcedae 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -40,8 +40,8 @@ impl From<u32> for VectorIdx {
     }
 }
 
-/// The size of the vector-clock to store inline
-/// clock vectors larger than this will be stored on the heap
+/// The size of the vector clock to store inline.
+/// Clock vectors larger than this will be stored on the heap.
 const SMALL_VECTOR: usize = 4;
 
 /// The time-stamps recorded in the data-race detector consist of both
@@ -136,7 +136,7 @@ impl Ord for VTimestamp {
 pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>);
 
 impl VClock {
-    /// Create a new vector-clock containing all zeros except
+    /// Create a new vector clock containing all zeros except
     /// for a value at the given index
     pub(super) fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock {
         if timestamp.time() == 0 {
@@ -185,8 +185,8 @@ impl VClock {
         }
     }
 
-    // Join the two vector-clocks together, this
-    // sets each vector-element to the maximum value
+    // Join the two vector clocks together, this
+    // sets each vector element to the maximum value
     // of that element in either of the two source elements.
     pub fn join(&mut self, other: &Self) {
         let rhs_slice = other.as_slice();
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index 1a3e9614f8a..95c010be2fd 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -77,7 +77,7 @@
 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167)
 // and here.
 //
-// 4. W_SC ; R_SC case requires the SC load to ignore all but last store maked SC (stores not marked SC are not
+// 4. W_SC ; R_SC case requires the SC load to ignore all but last store marked SC (stores not marked SC are not
 // affected). But this rule is applied to all loads in ReadsFromSet from the paper (last two lines of code), not just SC load.
 // This is implemented correctly in tsan11
 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295)
@@ -88,9 +88,11 @@ use std::collections::VecDeque;
 
 use rustc_data_structures::fx::FxHashMap;
 
+use super::AllocDataRaceHandler;
 use super::data_race::{GlobalState as DataRaceState, ThreadClockSet};
 use super::range_object_map::{AccessType, RangeObjectMap};
 use super::vector_clock::{VClock, VTimestamp, VectorIdx};
+use crate::concurrency::GlobalDataRaceHandler;
 use crate::*;
 
 pub type AllocState = StoreBufferAlloc;
@@ -459,8 +461,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
         if let (
-            crate::AllocExtra { weak_memory: Some(alloc_buffers), .. },
-            crate::MiriMachine { data_race: Some(global), threads, .. },
+            crate::AllocExtra {
+                data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)),
+                ..
+            },
+            crate::MiriMachine {
+                data_race: GlobalDataRaceHandler::Vclocks(global), threads, ..
+            },
         ) = this.get_alloc_extra_mut(alloc_id)?
         {
             if atomic == AtomicRwOrd::SeqCst {
@@ -484,9 +491,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Option<Scalar>> {
         let this = self.eval_context_ref();
         'fallback: {
-            if let Some(global) = &this.machine.data_race {
+            if let Some(global) = this.machine.data_race.as_vclocks_ref() {
                 let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
-                if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() {
+                if let Some(alloc_buffers) =
+                    this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref()
+                {
                     if atomic == AtomicReadOrd::SeqCst {
                         global.sc_read(&this.machine.threads);
                     }
@@ -534,8 +543,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?;
         if let (
-            crate::AllocExtra { weak_memory: Some(alloc_buffers), .. },
-            crate::MiriMachine { data_race: Some(global), threads, .. },
+            crate::AllocExtra {
+                data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)),
+                ..
+            },
+            crate::MiriMachine {
+                data_race: GlobalDataRaceHandler::Vclocks(global), threads, ..
+            },
         ) = this.get_alloc_extra_mut(alloc_id)?
         {
             if atomic == AtomicWriteOrd::SeqCst {
@@ -561,13 +575,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_ref();
 
-        if let Some(global) = &this.machine.data_race {
+        if let Some(global) = this.machine.data_race.as_vclocks_ref() {
             if atomic == AtomicReadOrd::SeqCst {
                 global.sc_read(&this.machine.threads);
             }
             let size = place.layout.size;
             let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?;
-            if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() {
+            if let Some(alloc_buffers) =
+                this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref()
+            {
                 let Some(buffer) =
                     alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?
                 else {
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 014b1299f2d..10570a37e5d 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -31,6 +31,8 @@ pub enum TerminationInfo {
     },
     Int2PtrWithStrictProvenance,
     Deadlock,
+    /// In GenMC mode, an execution can get stuck in certain cases. This is not an error.
+    GenmcStuckExecution,
     MultipleSymbolDefinitions {
         link_name: Symbol,
         first: SpanData,
@@ -75,6 +77,7 @@ impl fmt::Display for TerminationInfo {
             StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
             TreeBorrowsUb { title, .. } => write!(f, "{title}"),
             Deadlock => write!(f, "the evaluated program deadlocked"),
+            GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"),
             MultipleSymbolDefinitions { link_name, .. } =>
                 write!(f, "multiple definitions of symbol `{link_name}`"),
             SymbolShimClashing { link_name, .. } =>
@@ -235,6 +238,12 @@ pub fn report_error<'tcx>(
             StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>
                 Some("Undefined Behavior"),
             Deadlock => Some("deadlock"),
+            GenmcStuckExecution => {
+                // This case should only happen in GenMC mode. We treat it like a normal program exit.
+                assert!(ecx.machine.data_race.as_genmc_ref().is_some());
+                tracing::info!("GenMC: found stuck execution");
+                return Some((0, true));
+            }
             MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
         };
         #[rustfmt::skip]
@@ -639,8 +648,7 @@ impl<'tcx> MiriMachine<'tcx> {
             AccessedAlloc(AllocId(id), access_kind) =>
                 format!("{access_kind} to allocation with id {id}"),
             FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"),
-            RejectedIsolatedOp(ref op) =>
-                format!("{op} was made to return an error due to isolation"),
+            RejectedIsolatedOp(op) => format!("{op} was made to return an error due to isolation"),
             ProgressReport { .. } =>
                 format!("progress report: current operation being executed is here"),
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 7586b5efd4b..a90c6ab9d40 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -3,6 +3,7 @@
 use std::ffi::{OsStr, OsString};
 use std::panic::{self, AssertUnwindSafe};
 use std::path::PathBuf;
+use std::rc::Rc;
 use std::task::Poll;
 use std::{iter, thread};
 
@@ -14,6 +15,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
 
+use crate::concurrency::GenmcCtx;
 use crate::concurrency::thread::TlsAllocAction;
 use crate::diagnostics::report_leaks;
 use crate::shims::tls;
@@ -99,10 +101,6 @@ pub struct MiriConfig {
     pub validation: ValidationMode,
     /// Determines if Stacked Borrows or Tree Borrows is enabled.
     pub borrow_tracker: Option<BorrowTrackerMethod>,
-    /// Whether `core::ptr::Unique` receives special treatment.
-    /// If `true` then `Unique` is reborrowed with its own new tag and permission,
-    /// otherwise `Unique` is just another raw pointer.
-    pub unique_is_unique: bool,
     /// Controls alignment checking.
     pub check_alignment: AlignmentCheck,
     /// Action for an op requiring communication with the host.
@@ -117,16 +115,18 @@ pub struct MiriConfig {
     pub args: Vec<String>,
     /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
     pub seed: Option<u64>,
-    /// The stacked borrows pointer ids to report about
+    /// The stacked borrows pointer ids to report about.
     pub tracked_pointer_tags: FxHashSet<BorTag>,
     /// The allocation ids to report about.
     pub tracked_alloc_ids: FxHashSet<AllocId>,
     /// For the tracked alloc ids, also report read/write accesses.
     pub track_alloc_accesses: bool,
-    /// Determine if data race detection should be enabled
+    /// Determine if data race detection should be enabled.
     pub data_race_detector: bool,
-    /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled
+    /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled.
     pub weak_memory_emulation: bool,
+    /// Determine if we are running in GenMC mode. In this mode, Miri will explore multiple concurrent executions of the given program.
+    pub genmc_mode: bool,
     /// Track when an outdated (weak memory) load happens.
     pub track_outdated_loads: bool,
     /// Rate of spurious failures for compare_exchange_weak atomic operations,
@@ -137,7 +137,7 @@ pub struct MiriConfig {
     pub measureme_out: Option<String>,
     /// Which style to use for printing backtraces.
     pub backtrace_style: BacktraceStyle,
-    /// Which provenance to use for int2ptr casts
+    /// Which provenance to use for int2ptr casts.
     pub provenance_mode: ProvenanceMode,
     /// Whether to ignore any output by the program. This is helpful when debugging miri
     /// as its messages don't get intermingled with the program messages.
@@ -155,7 +155,7 @@ pub struct MiriConfig {
     pub gc_interval: u32,
     /// The number of CPUs to be reported by miri.
     pub num_cpus: u32,
-    /// Requires Miri to emulate pages of a certain size
+    /// Requires Miri to emulate pages of a certain size.
     pub page_size: Option<u64>,
     /// Whether to collect a backtrace when each allocation is created, just in case it leaks.
     pub collect_leak_backtraces: bool,
@@ -163,6 +163,10 @@ pub struct MiriConfig {
     pub address_reuse_rate: f64,
     /// Probability for address reuse across threads.
     pub address_reuse_cross_thread_rate: f64,
+    /// Round Robin scheduling with no preemption.
+    pub fixed_scheduling: bool,
+    /// Always prefer the intrinsic fallback body over the native Miri implementation.
+    pub force_intrinsic_fallback: bool,
 }
 
 impl Default for MiriConfig {
@@ -171,7 +175,6 @@ impl Default for MiriConfig {
             env: vec![],
             validation: ValidationMode::Shallow,
             borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
-            unique_is_unique: false,
             check_alignment: AlignmentCheck::Int,
             isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
             ignore_leaks: false,
@@ -184,6 +187,7 @@ impl Default for MiriConfig {
             track_alloc_accesses: false,
             data_race_detector: true,
             weak_memory_emulation: true,
+            genmc_mode: false,
             track_outdated_loads: false,
             cmpxchg_weak_failure_rate: 0.8, // 80%
             measureme_out: None,
@@ -200,6 +204,8 @@ impl Default for MiriConfig {
             collect_leak_backtraces: true,
             address_reuse_rate: 0.5,
             address_reuse_cross_thread_rate: 0.1,
+            fixed_scheduling: false,
+            force_intrinsic_fallback: false,
         }
     }
 }
@@ -230,16 +236,22 @@ impl<'tcx> MainThreadState<'tcx> {
                 match state.on_stack_empty(this)? {
                     Poll::Pending => {} // just keep going
                     Poll::Ready(()) => {
-                        // Give background threads a chance to finish by yielding the main thread a
-                        // couple of times -- but only if we would also preempt threads randomly.
-                        if this.machine.preemption_rate > 0.0 {
-                            // There is a non-zero chance they will yield back to us often enough to
-                            // make Miri terminate eventually.
-                            *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN };
-                        } else {
-                            // The other threads did not get preempted, so no need to yield back to
-                            // them.
+                        if this.machine.data_race.as_genmc_ref().is_some() {
+                            // In GenMC mode, we don't yield at the end of the main thread.
+                            // Instead, the `GenmcCtx` will ensure that unfinished threads get a chance to run at this point.
                             *self = Done;
+                        } else {
+                            // Give background threads a chance to finish by yielding the main thread a
+                            // couple of times -- but only if we would also preempt threads randomly.
+                            if this.machine.preemption_rate > 0.0 {
+                                // There is a non-zero chance they will yield back to us often enough to
+                                // make Miri terminate eventually.
+                                *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN };
+                            } else {
+                                // The other threads did not get preempted, so no need to yield back to
+                                // them.
+                                *self = Done;
+                            }
                         }
                     }
                 },
@@ -265,6 +277,17 @@ impl<'tcx> MainThreadState<'tcx> {
                 // Deal with our thread-local memory. We do *not* want to actually free it, instead we consider TLS
                 // to be like a global `static`, so that all memory reached by it is considered to "not leak".
                 this.terminate_active_thread(TlsAllocAction::Leak)?;
+
+                // Machine cleanup. Only do this if all threads have terminated; threads that are still running
+                // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
+                if this.have_all_terminated() {
+                    // Even if all threads have terminated, we have to beware of data races since some threads
+                    // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020,
+                    // https://github.com/rust-lang/miri/issues/2508).
+                    this.allow_data_races_all_threads_done();
+                    EnvVars::cleanup(this).expect("error during env var cleanup");
+                }
+
                 // Stop interpreter loop.
                 throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true });
             }
@@ -280,11 +303,16 @@ pub fn create_ecx<'tcx>(
     entry_id: DefId,
     entry_type: MiriEntryFnType,
     config: &MiriConfig,
+    genmc_ctx: Option<Rc<GenmcCtx>>,
 ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
     let typing_env = ty::TypingEnv::fully_monomorphized();
     let layout_cx = LayoutCx::new(tcx, typing_env);
-    let mut ecx =
-        InterpCx::new(tcx, rustc_span::DUMMY_SP, typing_env, MiriMachine::new(config, layout_cx));
+    let mut ecx = InterpCx::new(
+        tcx,
+        rustc_span::DUMMY_SP,
+        typing_env,
+        MiriMachine::new(config, layout_cx, genmc_ctx),
+    );
 
     // Some parts of initialization require a full `InterpCx`.
     MiriMachine::late_init(&mut ecx, config, {
@@ -438,12 +466,17 @@ pub fn eval_entry<'tcx>(
     tcx: TyCtxt<'tcx>,
     entry_id: DefId,
     entry_type: MiriEntryFnType,
-    config: MiriConfig,
+    config: &MiriConfig,
+    genmc_ctx: Option<Rc<GenmcCtx>>,
 ) -> Option<i32> {
     // Copy setting before we move `config`.
     let ignore_leaks = config.ignore_leaks;
 
-    let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config).report_err() {
+    if let Some(genmc_ctx) = &genmc_ctx {
+        genmc_ctx.handle_execution_start();
+    }
+
+    let mut ecx = match create_ecx(tcx, entry_id, entry_type, config, genmc_ctx).report_err() {
         Ok(v) => v,
         Err(err) => {
             let (kind, backtrace) = err.into_parts();
@@ -462,21 +495,21 @@ pub fn eval_entry<'tcx>(
     // `Ok` can never happen; the interpreter loop always exits with an "error"
     // (but that "error" might be just "regular program termination").
     let Err(err) = res.report_err();
+
     // Show diagnostic, if any.
     let (return_code, leak_check) = report_error(&ecx, err)?;
 
-    // If we get here there was no fatal error.
-
-    // Machine cleanup. Only do this if all threads have terminated; threads that are still running
-    // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
-    if ecx.have_all_terminated() {
-        // Even if all threads have terminated, we have to beware of data races since some threads
-        // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020,
-        // https://github.com/rust-lang/miri/issues/2508).
-        ecx.allow_data_races_all_threads_done();
-        EnvVars::cleanup(&mut ecx).expect("error during env var cleanup");
+    // We inform GenMC that the execution is complete.
+    if let Some(genmc_ctx) = ecx.machine.data_race.as_genmc_ref()
+        && let Err(error) = genmc_ctx.handle_execution_end(&ecx)
+    {
+        // FIXME(GenMC): Improve error reporting.
+        tcx.dcx().err(format!("GenMC returned an error: \"{error}\""));
+        return None;
     }
 
+    // If we get here there was no fatal error.
+
     // Possibly check for memory leaks.
     if leak_check && !ignore_leaks {
         // Check for thread leaks.
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index a3aa8bbbfb3..8e7c9edfcc0 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -932,12 +932,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
     }
 
-    /// Check that the ABI is what we expect.
-    fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> {
+    /// Check that the calling convention is what we expect.
+    fn check_callconv<'a>(
+        &self,
+        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+        exp_abi: Conv,
+    ) -> InterpResult<'a, ()> {
         if fn_abi.conv != exp_abi {
             throw_ub_format!(
-                "calling a function with ABI {:?} using caller ABI {:?}",
-                exp_abi,
+                "calling a function with calling convention {exp_abi} using caller calling convention {}",
                 fn_abi.conv
             );
         }
@@ -973,7 +976,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         exp_abi: Conv,
         link_name: Symbol,
     ) -> InterpResult<'tcx, ()> {
-        self.check_abi(abi, exp_abi)?;
+        self.check_callconv(abi, exp_abi)?;
         if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
             // If compiler-builtins is providing the symbol, then don't treat it as a clash.
             // We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs
index dcafa7b6cab..2eb8086f578 100644
--- a/src/tools/miri/src/intrinsics/atomic.rs
+++ b/src/tools/miri/src/intrinsics/atomic.rs
@@ -149,7 +149,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
 
         // Perform regular load.
         let val = this.read_scalar(val)?;
-        // Perform atomic store
+        // Perform atomic store.
         this.write_scalar_atomic(val, &place, atomic)?;
         interp_ok(())
     }
@@ -161,7 +161,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let [] = check_intrinsic_arg_count(args)?;
         let _ = atomic;
-        //FIXME: compiler fences are currently ignored
+        // FIXME, FIXME(GenMC): compiler fences are currently ignored (also ignored in GenMC mode)
         interp_ok(())
     }
 
@@ -199,23 +199,16 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch");
         }
 
-        match atomic_op {
-            AtomicOp::Min => {
-                let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?;
-                this.write_immediate(*old, dest)?; // old value is returned
-                interp_ok(())
-            }
-            AtomicOp::Max => {
-                let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?;
-                this.write_immediate(*old, dest)?; // old value is returned
-                interp_ok(())
-            }
-            AtomicOp::MirOp(op, not) => {
-                let old = this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?;
-                this.write_immediate(*old, dest)?; // old value is returned
-                interp_ok(())
-            }
-        }
+        let old = match atomic_op {
+            AtomicOp::Min =>
+                this.atomic_min_max_scalar(&place, rhs, /* min */ true, atomic)?,
+            AtomicOp::Max =>
+                this.atomic_min_max_scalar(&place, rhs, /* min */ false, atomic)?,
+            AtomicOp::MirOp(op, not) =>
+                this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?,
+        };
+        this.write_immediate(*old, dest)?; // old value is returned
+        interp_ok(())
     }
 
     fn atomic_exchange(
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 3334c0b5edf..982fbc31811 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -28,6 +28,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         let this = self.eval_context_mut();
 
+        // Force use of fallback body, if available.
+        if this.machine.force_intrinsic_fallback
+            && !this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden
+        {
+            return interp_ok(Some(ty::Instance {
+                def: ty::InstanceKind::Item(instance.def_id()),
+                args: instance.args,
+            }));
+        }
+
         // See if the core engine can handle this intrinsic.
         if this.eval_intrinsic(instance, args, dest, ret)? {
             return interp_ok(None);
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index de5da6ec898..c9250ba1b81 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -506,7 +506,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 let dest_len = u32::try_from(dest_len).unwrap();
-                let bitmask_len = u32::try_from(bitmask_len).unwrap();
                 for i in 0..dest_len {
                     let bit_i = simd_bitmask_index(i, dest_len, this.data_layout().endian);
                     let mask = mask & 1u64.strict_shl(bit_i);
@@ -517,17 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let val = if mask != 0 { yes } else { no };
                     this.write_immediate(*val, &dest)?;
                 }
-                for i in dest_len..bitmask_len {
-                    // If the mask is "padded", ensure that padding is all-zero.
-                    // This deliberately does not use `simd_bitmask_index`; these bits are outside
-                    // the bitmask. It does not matter in which order we check them.
-                    let mask = mask & 1u64.strict_shl(i);
-                    if mask != 0 {
-                        throw_ub_format!(
-                            "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits"
-                        );
-                    }
-                }
+                // The remaining bits of the mask are ignored.
             }
             // Converts a "vector of bool" into a bitmask.
             "bitmask" => {
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e03611e9b50..329a7e56bc0 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(variant_count)]
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
-#![feature(let_chains)]
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]
@@ -61,7 +60,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;
@@ -133,6 +132,7 @@ pub use crate::concurrency::thread::{
     BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId,
     ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind,
 };
+pub use crate::concurrency::{GenmcConfig, GenmcCtx};
 pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
 };
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 55aa3d6fa68..1c6c7894cb4 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -6,13 +6,14 @@ use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
 use std::collections::hash_map::Entry;
 use std::path::Path;
+use std::rc::Rc;
 use std::{fmt, process};
 
 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;
@@ -27,9 +28,10 @@ use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::{Span, SpanData, Symbol};
 use rustc_target::callconv::FnAbi;
 
+use crate::alloc_addresses::EvalContextExt;
 use crate::concurrency::cpu_affinity::{self, CpuAffinityMask};
 use crate::concurrency::data_race::{self, NaReadType, NaWriteType};
-use crate::concurrency::weak_memory;
+use crate::concurrency::{AllocDataRaceHandler, GenmcCtx, GlobalDataRaceHandler, weak_memory};
 use crate::*;
 
 /// First real-time signal.
@@ -332,12 +334,10 @@ impl ProvenanceExtra {
 pub struct AllocExtra<'tcx> {
     /// Global state of the borrow tracker, if enabled.
     pub borrow_tracker: Option<borrow_tracker::AllocState>,
-    /// Data race detection via the use of a vector-clock.
-    /// This is only added if it is enabled.
-    pub data_race: Option<data_race::AllocState>,
-    /// Weak memory emulation via the use of store buffers.
-    /// This is only added if it is enabled.
-    pub weak_memory: Option<weak_memory::AllocState>,
+    /// Extra state for data race detection.
+    ///
+    /// Invariant: The enum variant must match the enum variant in the `data_race` field on `MiriMachine`
+    pub data_race: AllocDataRaceHandler,
     /// A backtrace to where this allocation was allocated.
     /// As this is recorded for leak reports, it only exists
     /// if this allocation is leakable. The backtrace is not
@@ -360,11 +360,10 @@ impl<'tcx> Clone for AllocExtra<'tcx> {
 
 impl VisitProvenance for AllocExtra<'_> {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _, sync: _ } = self;
+        let AllocExtra { borrow_tracker, data_race, backtrace: _, sync: _ } = self;
 
         borrow_tracker.visit_provenance(visit);
         data_race.visit_provenance(visit);
-        weak_memory.visit_provenance(visit);
     }
 }
 
@@ -447,8 +446,12 @@ pub struct MiriMachine<'tcx> {
     /// Global data for borrow tracking.
     pub borrow_tracker: Option<borrow_tracker::GlobalState>,
 
-    /// Data race detector global data.
-    pub data_race: Option<data_race::GlobalState>,
+    /// Depending on settings, this will be `None`,
+    /// global data for a data race detector,
+    /// or the context required for running in GenMC mode.
+    ///
+    /// Invariant: The enum variant must match the enum variant of `AllocDataRaceHandler` in the `data_race` field of all `AllocExtra`.
+    pub data_race: GlobalDataRaceHandler,
 
     /// Ptr-int-cast module global data.
     pub alloc_addresses: alloc_addresses::GlobalState,
@@ -544,9 +547,6 @@ pub struct MiriMachine<'tcx> {
     /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded.
     pub(crate) mute_stdout_stderr: bool,
 
-    /// Whether weak memory emulation is enabled
-    pub(crate) weak_memory: bool,
-
     /// The probability of the active thread being preempted at the end of each basic block.
     pub(crate) preemption_rate: f64,
 
@@ -614,10 +614,17 @@ pub struct MiriMachine<'tcx> {
 
     /// Cache for `mangle_internal_symbol`.
     pub(crate) mangle_internal_symbol_cache: FxHashMap<&'static str, String>,
+
+    /// Always prefer the intrinsic fallback body over the native Miri implementation.
+    pub force_intrinsic_fallback: bool,
 }
 
 impl<'tcx> MiriMachine<'tcx> {
-    pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self {
+    pub(crate) fn new(
+        config: &MiriConfig,
+        layout_cx: LayoutCx<'tcx>,
+        genmc_ctx: Option<Rc<GenmcCtx>>,
+    ) -> Self {
         let tcx = layout_cx.tcx();
         let local_crates = helpers::get_local_crates(tcx);
         let layouts =
@@ -636,7 +643,14 @@ impl<'tcx> MiriMachine<'tcx> {
         });
         let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
         let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config));
-        let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
+        let data_race = if config.genmc_mode {
+            // `genmc_ctx` persists across executions, so we don't create a new one here.
+            GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap())
+        } else if config.data_race_detector {
+            GlobalDataRaceHandler::Vclocks(Box::new(data_race::GlobalState::new(config)))
+        } else {
+            GlobalDataRaceHandler::None
+        };
         // Determine page size, stack address, and stack size.
         // These values are mostly meaningless, but the stack address is also where we start
         // allocating physical integer addresses for all allocations.
@@ -669,7 +683,7 @@ impl<'tcx> MiriMachine<'tcx> {
             cpu_affinity::MAX_CPUS,
             config.num_cpus
         );
-        let threads = ThreadManager::default();
+        let threads = ThreadManager::new(config);
         let mut thread_cpu_affinity = FxHashMap::default();
         if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") {
             thread_cpu_affinity
@@ -709,7 +723,6 @@ impl<'tcx> MiriMachine<'tcx> {
             check_alignment: config.check_alignment,
             cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
             mute_stdout_stderr: config.mute_stdout_stderr,
-            weak_memory: config.weak_memory_emulation,
             preemption_rate: config.preemption_rate,
             report_progress: config.report_progress,
             basic_block_count: 0,
@@ -760,6 +773,7 @@ impl<'tcx> MiriMachine<'tcx> {
             reject_in_isolation_warned: Default::default(),
             int2ptr_warned: Default::default(),
             mangle_internal_symbol_cache: Default::default(),
+            force_intrinsic_fallback: config.force_intrinsic_fallback,
         }
     }
 
@@ -835,16 +849,25 @@ impl<'tcx> MiriMachine<'tcx> {
             .as_ref()
             .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine));
 
-        let data_race = ecx.machine.data_race.as_ref().map(|data_race| {
-            data_race::AllocState::new_allocation(
-                data_race,
-                &ecx.machine.threads,
-                size,
-                kind,
-                ecx.machine.current_span(),
-            )
-        });
-        let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation);
+        let data_race = match &ecx.machine.data_race {
+            GlobalDataRaceHandler::None => AllocDataRaceHandler::None,
+            GlobalDataRaceHandler::Vclocks(data_race) =>
+                AllocDataRaceHandler::Vclocks(
+                    data_race::AllocState::new_allocation(
+                        data_race,
+                        &ecx.machine.threads,
+                        size,
+                        kind,
+                        ecx.machine.current_span(),
+                    ),
+                    data_race.weak_memory.then(weak_memory::AllocState::new_allocation),
+                ),
+            GlobalDataRaceHandler::Genmc(_genmc_ctx) => {
+                // GenMC learns about new allocations directly from the alloc_addresses module,
+                // since it has to be able to control the address at which they are placed.
+                AllocDataRaceHandler::Genmc
+            }
+        };
 
         // If an allocation is leaked, we want to report a backtrace to indicate where it was
         // allocated. We don't need to record a backtrace for allocations which are allowed to
@@ -862,13 +885,7 @@ impl<'tcx> MiriMachine<'tcx> {
                 .insert(id, (ecx.machine.current_span(), None));
         }
 
-        interp_ok(AllocExtra {
-            borrow_tracker,
-            data_race,
-            weak_memory,
-            backtrace,
-            sync: FxHashMap::default(),
-        })
+        interp_ok(AllocExtra { borrow_tracker, data_race, backtrace, sync: FxHashMap::default() })
     }
 }
 
@@ -909,7 +926,6 @@ impl VisitProvenance for MiriMachine<'_> {
             check_alignment: _,
             cmpxchg_weak_failure_rate: _,
             mute_stdout_stderr: _,
-            weak_memory: _,
             preemption_rate: _,
             report_progress: _,
             basic_block_count: _,
@@ -934,6 +950,7 @@ impl VisitProvenance for MiriMachine<'_> {
             reject_in_isolation_warned: _,
             int2ptr_warned: _,
             mangle_internal_symbol_cache: _,
+            force_intrinsic_fallback: _,
         } = self;
 
         threads.visit_provenance(visit);
@@ -1203,9 +1220,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &mut InterpCx<'tcx, Self>,
         val: ImmTy<'tcx>,
     ) -> InterpResult<'tcx, ImmTy<'tcx>> {
-        crate::math::apply_random_float_error_to_imm(
-            ecx, val, 2 /* log2(4) */
-        )
+        crate::math::apply_random_float_error_to_imm(ecx, val, 2 /* log2(4) */)
     }
 
     #[inline(always)]
@@ -1380,7 +1395,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         _tcx: TyCtxtAt<'tcx>,
         machine: &Self,
         alloc_extra: &AllocExtra<'tcx>,
-        _ptr: Pointer,
+        ptr: Pointer,
         (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
         range: AllocRange,
     ) -> InterpResult<'tcx> {
@@ -1388,15 +1403,25 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             machine
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read));
         }
-        if let Some(data_race) = &alloc_extra.data_race {
-            data_race.read(alloc_id, range, NaReadType::Read, None, machine)?;
+        // The order of checks is deliberate, to prefer reporting a data race over a borrow tracker error.
+        match &machine.data_race {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                genmc_ctx.memory_load(machine, ptr.addr(), range.size)?,
+            GlobalDataRaceHandler::Vclocks(_data_race) => {
+                let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &alloc_extra.data_race
+                else {
+                    unreachable!();
+                };
+                data_race.read(alloc_id, range, NaReadType::Read, None, machine)?;
+                if let Some(weak_memory) = weak_memory {
+                    weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap());
+                }
+            }
         }
         if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
         }
-        if let Some(weak_memory) = &alloc_extra.weak_memory {
-            weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
-        }
         interp_ok(())
     }
 
@@ -1405,7 +1430,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         _tcx: TyCtxtAt<'tcx>,
         machine: &mut Self,
         alloc_extra: &mut AllocExtra<'tcx>,
-        _ptr: Pointer,
+        ptr: Pointer,
         (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
         range: AllocRange,
     ) -> InterpResult<'tcx> {
@@ -1413,15 +1438,26 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             machine
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write));
         }
-        if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?;
+        match &machine.data_race {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Genmc(genmc_ctx) => {
+                genmc_ctx.memory_store(machine, ptr.addr(), range.size)?;
+            }
+            GlobalDataRaceHandler::Vclocks(_global_state) => {
+                let AllocDataRaceHandler::Vclocks(data_race, weak_memory) =
+                    &mut alloc_extra.data_race
+                else {
+                    unreachable!()
+                };
+                data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?;
+                if let Some(weak_memory) = weak_memory {
+                    weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap());
+                }
+            }
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
         }
-        if let Some(weak_memory) = &alloc_extra.weak_memory {
-            weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
-        }
         interp_ok(())
     }
 
@@ -1430,7 +1466,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         _tcx: TyCtxtAt<'tcx>,
         machine: &mut Self,
         alloc_extra: &mut AllocExtra<'tcx>,
-        _ptr: Pointer,
+        ptr: Pointer,
         (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra),
         size: Size,
         align: Align,
@@ -1439,14 +1475,20 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if machine.tracked_alloc_ids.contains(&alloc_id) {
             machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
         }
-        if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(
-                alloc_id,
-                alloc_range(Size::ZERO, size),
-                NaWriteType::Deallocate,
-                None,
-                machine,
-            )?;
+        match &machine.data_race {
+            GlobalDataRaceHandler::None => {}
+            GlobalDataRaceHandler::Genmc(genmc_ctx) =>
+                genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?,
+            GlobalDataRaceHandler::Vclocks(_global_state) => {
+                let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap();
+                data_race.write(
+                    alloc_id,
+                    alloc_range(Size::ZERO, size),
+                    NaWriteType::Deallocate,
+                    None,
+                    machine,
+                )?;
+            }
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?;
@@ -1533,7 +1575,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
             salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL),
-            data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()),
+            data_race: ecx
+                .machine
+                .data_race
+                .as_vclocks_ref()
+                .map(|_| data_race::FrameState::default()),
         };
 
         interp_ok(frame.with_extra(extra))
@@ -1679,7 +1725,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         if let Some(data_race) =
             &machine.threads.active_thread_stack().last().unwrap().extra.data_race
         {
-            data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine);
+            data_race.local_moved_to_memory(
+                local,
+                alloc_info.data_race.as_vclocks_mut().unwrap(),
+                machine,
+            );
         }
         interp_ok(())
     }
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index 0258a76c3e7..1a43e229725 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -92,8 +92,7 @@ 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 (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,
@@ -114,11 +113,17 @@ 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 std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap()
-                    != _lib_path.to_str().unwrap()
+                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()
                 {
                     return None;
                 }
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 18af8214876..b5ed5ea837b 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -85,6 +85,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Now we make a function call, and pass `data` as first and only argument.
         let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?;
         trace!("try_fn: {:?}", f_instance);
+        #[allow(clippy::cloned_ref_to_slice_refs)] // the code is clearer as-is
         this.call_function(
             f_instance,
             ExternAbi::Rust,
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index c7e2c4d507b..30ec0aefcbf 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -42,7 +42,7 @@ pub fn prctl<'tcx>(
             ecx.check_ptr_access(
                 name.to_pointer(ecx)?,
                 Size::from_bytes(TASK_COMM_LEN),
-                CheckInAllocMsg::MemoryAccessTest,
+                CheckInAllocMsg::MemoryAccess,
             )?;
             let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
             assert_eq!(res, ThreadNameResult::Ok);
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 41be9df7e2d..156814a26fa 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -226,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         trace!("Reading from FD {}, size {}", fd_num, count);
 
         // Check that the *entire* buffer is actually valid memory.
-        this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?;
+        this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?;
 
         // We cap the number of read bytes to the largest value that we are able to fit in both the
         // host's and target's `isize`. This saves us from having to handle overflows later.
@@ -292,7 +292,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Isolation check is done via `FileDescription` trait.
 
         // Check that the *entire* buffer is actually valid memory.
-        this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?;
+        this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?;
 
         // We cap the number of written bytes to the largest value that we are able to fit in both the
         // host's and target's `isize`. This saves us from having to handle overflows later.
diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py
index a9d09ac7a9d..40bfe7f845f 100755
--- a/src/tools/miri/test-cargo-miri/run-test.py
+++ b/src/tools/miri/test-cargo-miri/run-test.py
@@ -142,24 +142,19 @@ def test_cargo_miri_run():
     )
 
 def test_cargo_miri_test():
-    # rustdoc is not run on foreign targets
-    is_foreign = ARGS.target is not None
-    default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
-    filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
-
     test("`cargo miri test`",
         cargo_miri("test"),
-        default_ref, "test.empty.ref",
+        "test.default.stdout.ref", "test.empty.ref",
         env={'MIRIFLAGS': "-Zmiri-seed=4242"},
     )
     test("`cargo miri test` (no isolation, no doctests)",
         cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml`
-        "test.cross-target.stdout.ref", "test.empty.ref",
+        "test.no-doc.stdout.ref", "test.empty.ref",
         env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
     )
     test("`cargo miri test` (with filter)",
         cargo_miri("test") + ["--", "--format=pretty", "pl"],
-        filter_ref, "test.empty.ref",
+        "test.filter.stdout.ref", "test.empty.ref",
     )
     test("`cargo miri test` (test target)",
         cargo_miri("test") + ["--test", "test", "--", "--format=pretty"],
@@ -171,7 +166,7 @@ def test_cargo_miri_test():
     )
     test("`cargo miri t` (subcrate, no isolation)",
         cargo_miri("t") + ["-p", "subcrate"],
-        "test.subcrate.cross-target.stdout.ref" if is_foreign else "test.subcrate.stdout.ref",
+        "test.subcrate.stdout.ref",
         "test.empty.ref",
         env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
     )
@@ -181,12 +176,12 @@ def test_cargo_miri_test():
     )
     test("`cargo miri test` (custom target dir)",
         cargo_miri("test") + ["--target-dir=custom-test"],
-        default_ref, "test.empty.ref",
+        "test.default.stdout.ref", "test.empty.ref",
     )
     del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it
     test("`cargo miri test` (config-cli)",
         cargo_miri("test") + ["--config=build.target-dir=\"config-cli\""],
-        default_ref, "test.empty.ref",
+        "test.default.stdout.ref", "test.empty.ref",
     )
     if ARGS.multi_target:
         test_cargo_miri_multi_target()
diff --git a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref
deleted file mode 100644
index 59b4deb1ff3..00000000000
--- a/src/tools/miri/test-cargo-miri/test.filter.cross-target.stdout.ref
+++ /dev/null
@@ -1,12 +0,0 @@
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in $TIME
-
-imported main
-
-running 1 test
-test simple ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME
-
diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref
index 567c5db07d0..a376530a8cf 100644
--- a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref
@@ -20,3 +20,13 @@ running 6 tests
 ...i..
 test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
 
+
+running 5 tests
+.....
+test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
+
+running 5 tests
+.....
+test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref
index 2ef124e4de8..2ef124e4de8 100644
--- a/src/tools/miri/test-cargo-miri/test.cross-target.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref
diff --git a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref
deleted file mode 100644
index 436e6e4fbbb..00000000000
--- a/src/tools/miri/test-cargo-miri/test.subcrate.cross-target.stdout.ref
+++ /dev/null
@@ -1,11 +0,0 @@
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
-
-
-running 0 tests
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
-
-subcrate testing
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
index 53760b05a31..f75f306e5a6 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
@@ -1,6 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 // Joining itself is undefined behavior.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
index e3d5da26aea..68dce8f8654 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
@@ -1,5 +1,7 @@
 //@ignore-target: windows # No pthreads on Windows
 //@error-in-other-file: deadlock
+// We are making scheduler assumptions here.
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
index 3a985122e22..3a932404238 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
@@ -1,5 +1,7 @@
 //@ignore-target: windows # No pthreads on Windows
 //@error-in-other-file: deadlock
+// We are making scheduler assumptions here.
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
index 6d7bb80d8e6..3b217388463 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
@@ -1,5 +1,7 @@
 //@ignore-target: windows # No pthreads on Windows
 //@error-in-other-file: deadlock
+// We are making scheduler assumptions here.
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
index 3ee2bf14f9f..2980d257a29 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs
@@ -1,6 +1,6 @@
 //@only-target: windows # Uses win32 api functions
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 // On windows, joining main is not UB, but it will block a thread forever.
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
index eee2979f3cf..85672ec860f 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs
@@ -1,6 +1,6 @@
 //@only-target: windows # Uses win32 api functions
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 // On windows, a thread joining itself is not UB, but it will deadlock.
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
index 5a226c6a44b..cc3daa47e00 100644
--- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation
+error: Undefined Behavior: memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation
   --> tests/fail-dep/libc/affinity.rs:LL:CC
    |
 LL |     let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>() + 1, &cpuset) };
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation
    |
    = 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-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
index 3a832bb0ce0..5c80f6425ea 100644
--- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency
 //@ignore-target: windows # No libc env support on Windows
 
 use std::{env, thread};
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
index 0d893663fd6..9dc554030c0 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
@@ -1,7 +1,7 @@
 //@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 use std::thread;
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
index 9fed47c17d4..5297a329775 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
@@ -1,7 +1,7 @@
 //@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 use std::thread;
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
index 45f6bf6da09..314ce90cfb5 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
@@ -4,7 +4,7 @@
 //! to be considered synchronized.
 //@only-target: linux android illumos
 // ensure deterministic schedule
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::convert::TryInto;
 use std::thread;
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
index 059b24cb8c0..f6f2e2b9312 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 //@only-target: linux android illumos
diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
index 6d3ff176c35..5690277a046 100644
--- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
   --> tests/fail-dep/libc/memchr_null.rs:LL:CC
    |
 LL |         libc::memchr(ptr::null(), 0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer
    |
    = 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-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
index a4ca205c377..bd3a0719fa3 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
   --> tests/fail-dep/libc/memcmp_null.rs:LL:CC
    |
 LL |         libc::memcmp(ptr::null(), ptr::null(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer
    |
    = 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-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
index d7b046c1823..2044c154761 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail-dep/libc/memcmp_zero.rs:LL:CC
    |
 LL |         libc::memcmp(ptr.cast(), ptr.cast(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
index 336113e3440..789e9daf43b 100644
--- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail-dep/libc/memcpy_zero.rs:LL:CC
    |
 LL |         libc::memcpy(to.cast(), from.cast(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
index ce759f3e17a..27e7a9855d1 100644
--- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
   --> tests/fail-dep/libc/memrchr_null.rs:LL:CC
    |
 LL |         libc::memrchr(ptr::null(), 0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer
    |
    = 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-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
index 8413e118819..0699dec6556 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
@@ -2,7 +2,7 @@
 //! faulty logic around `release_clock` that led to this code not reporting a data race.
 //~^^ERROR: deadlock
 //@ignore-target: windows # no libc socketpair on Windows
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 use std::thread;
 
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
index 55491da9f60..37fac436ff3 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
@@ -1,7 +1,7 @@
 //! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
 //! faulty logic around `release_clock` that led to this code not reporting a data race.
 //@ignore-target: windows # no libc socketpair on Windows
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 use std::thread;
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
index d3e4c43f2b7..b3839859500 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs
@@ -2,7 +2,7 @@
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 // test_race depends on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 use std::thread;
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
index 4f951acb2c3..7d84d87ebbb 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs
@@ -2,7 +2,7 @@
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 // test_race depends on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@error-in-other-file: deadlock
 
 use std::thread;
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs
index 2097126e16b..4a87411d755 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs
@@ -1,5 +1,5 @@
 //@error-in-other-file: aborted
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 #![feature(allocator_api)]
 
diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr
index 3642f3f28ca..fa84da841fd 100644
--- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr
+++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr
@@ -2,7 +2,7 @@ memory allocation of 4 bytes failed
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
index 49de3dd0b10..dd7dae9cecf 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs
@@ -1,6 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@error-in-other-file: expected a pointer to 4 bytes of memory
+//@error-in-other-file: pointer not dereferenceable
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
index cd27bb818e7..0e6d838dfff 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation
    |
    = 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/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
index cd27bb818e7..0e6d838dfff 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation
    |
    = 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/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
index 04e5765371e..861173f5496 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
index 04e5765371e..861173f5496 100644
--- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
   --> RUSTLIB/alloc/src/boxed.rs:LL:CC
    |
 LL |         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
index 0061679eaa4..31f1a22f9f6 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
@@ -1,8 +1,6 @@
 //! Make sure that a retag acts like a write for the data race model.
 //@revisions: stack tree
-//@compile-flags: -Zmiri-preemption-rate=0
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@[tree]compile-flags: -Zmiri-tree-borrows
 #[derive(Copy, Clone)]
 struct SendPtr(*mut u8);
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs
index 65eca07a070..54b3280e71a 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs
@@ -6,6 +6,6 @@ fn main() {
         let b = Box::new(42);
         &*b as *const i32
     };
-    let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/
+    let x = unsafe { p.offset(42) }; //~ ERROR: /in-bounds pointer arithmetic failed: .* has been freed/
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr
index 076d6880461..fd1a5e7faaf 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
   --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC
    |
 LL |     let x = unsafe { p.offset(42) };
-   |                      ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+   |                      ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointers/dangling_pointer_project_underscore_let.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs
index 22a5ce8ea74..02ea09efab6 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs
@@ -7,6 +7,6 @@ fn main() {
         &*b as *const i32 as *const (u8, u8, u8, u8)
     };
     unsafe {
-        let _ = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic
+        let _ = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed
     }
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr
index ffb525e3981..ffb8bc9507b 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
   --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC
    |
 LL |         let _ = (*p).1;
-   |                 ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+   |                 ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs
index fc10a826c1e..7ab295cb6c6 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs
@@ -7,6 +7,6 @@ fn main() {
         &*b as *const i32 as *const (u8, u8, u8, u8)
     };
     unsafe {
-        let _: u8 = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic
+        let _: u8 = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed
     }
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr
index 14dfa43b2d6..cf3e1db13d3 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
   --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC
    |
 LL |         let _: u8 = (*p).1;
-   |                     ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+   |                     ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointers/dangling_pointer_project_underscore_match.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs
index 8541da84857..2855dd13fdc 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs
@@ -8,7 +8,7 @@ fn main() {
     };
     unsafe {
         match (*p).1 {
-            //~^ ERROR: out-of-bounds pointer arithmetic
+            //~^ ERROR: in-bounds pointer arithmetic failed
             _ => {}
         }
     }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr
index ff39e147573..e2d04433b63 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
   --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC
    |
 LL |         match (*p).1 {
-   |               ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
+   |               ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling
    |
    = 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/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
index 99194d6e072..5a2b85696ab 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC
    |
 LL |     unsafe { &(*x).0 as *const i32 }
-   |              ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
+   |              ^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
index 09a201983b1..ad4280c2d74 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC
    |
 LL |     let _y = unsafe { &*x as *const u32 };
-   |                       ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
+   |                       ^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
index d87a8bc59e9..3135db9dc6d 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer
   --> tests/fail/dangling_pointers/null_pointer_deref.rs:LL:CC
    |
 LL |     let x: i32 = unsafe { *std::ptr::null() };
-   |                           ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
+   |                           ^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer
    |
    = 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/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
index 39d861a6388..012b38ee5a6 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer
   --> tests/fail/dangling_pointers/null_pointer_write.rs:LL:CC
    |
 LL |     unsafe { *std::ptr::null_mut() = 0i32 };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer
    |
    = 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/dangling_pointers/out_of_bounds_project.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs
index b596ba428ae..7a2ad483d01 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs
@@ -7,6 +7,6 @@ fn main() {
     let ptr = addr_of!(v).cast::<(u32, u32, u32)>();
     unsafe {
         let _field = addr_of!((*ptr).1); // still just in-bounds
-        let _field = addr_of!((*ptr).2); //~ ERROR: out-of-bounds pointer arithmetic
+        let _field = addr_of!((*ptr).2); //~ ERROR: in-bounds pointer arithmetic failed
     }
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
index 27a437c7483..c11ccdb45a7 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation
   --> tests/fail/dangling_pointers/out_of_bounds_project.rs:LL:CC
    |
 LL |         let _field = addr_of!((*ptr).2);
-   |                      ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
+   |                      ^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation
    |
    = 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/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
index 595a229baa5..78a7b7e460b 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v: Vec<u16> = vec![1, 2];
     // This read is also misaligned. We make sure that the OOB message has priority.
-    let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: expected a pointer to 2 bytes of memory
+    let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: attempting to access 2 bytes
     panic!("this should never print: {}", x);
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
index 813bcef54f1..1de4b806da2 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
+error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
   --> tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC
    |
 LL |     let x = unsafe { *v.as_ptr().wrapping_byte_add(5) };
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
    |
    = 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/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
index 054e1c66cc1..f83601b44f8 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs
@@ -1,5 +1,5 @@
 fn main() {
     let mut v: Vec<u16> = vec![1, 2];
     // This read is also misaligned. We make sure that the OOB message has priority.
-    unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: expected a pointer to 2 bytes of memory
+    unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: attempting to access 2 bytes
 }
diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
index 1056a739a43..db16d70704e 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
+error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
   --> tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC
    |
 LL |     unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes
    |
    = 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/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
index 9061121494d..e97427ab7eb 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC
    |
 LL |     let _ref = unsafe { &mut *(LEAK as *mut i32) };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
index 3e7aac4724d..79e27fa3461 100644
--- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
+++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/dangling_pointers/wild_pointer_deref.rs:LL:CC
    |
 LL |     let x = unsafe { *p };
-   |                      ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
+   |                      ^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/data_race/alloc_read_race.rs b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs
index 312b7ba05d3..7c511698994 100644
--- a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs
+++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::mem::MaybeUninit;
 use std::ptr::null_mut;
diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs
index f1f308b37e7..ba8a888de9e 100644
--- a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs
+++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::ptr::null_mut;
 use std::sync::atomic::{AtomicPtr, Ordering};
diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs
index 4003892f0a6..8cce54603ce 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
index c67ce65eb34..b6c0ef37cb9 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
index 5e328740e85..03ae6895c57 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs
index e0876a93fdd..4a5edf5cc14 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs
index 1010216a497..e8d930a51de 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
index fdc0f9e20f0..4c67d2d7654 100644
--- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs
index dffafe3cfaa..fbb2c01e5a9 100644
--- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs
+++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::mem;
 use std::thread::{sleep, spawn};
diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs
index 8dc35c7ea72..7431bc589ff 100644
--- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs
+++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::mem;
 use std::thread::{sleep, spawn};
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs
index d0a28482054..999cc2392f5 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 #![feature(rustc_attrs)]
 
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
index f56c44cabc2..bd3b037e583 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 #![feature(rustc_attrs)]
 
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs
index c67e03d362b..e3d06660aab 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::ptr::null_mut;
 use std::sync::atomic::{AtomicPtr, Ordering};
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs
index a16ea25e11c..90e87f8c495 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 #![feature(rustc_attrs)]
 
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
index f3855e33c98..d9b1af80af4 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 #![feature(rustc_attrs)]
 
diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs
index 8e63bc1dc7b..c1ab1942c68 100644
--- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs
+++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::ptr::null_mut;
 use std::sync::atomic::{AtomicPtr, Ordering};
diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs
index 53050608d27..67af6862737 100644
--- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs
+++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::thread::spawn;
 
diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs
index 5dfb260c20b..b1eb1dda6d8 100644
--- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs
+++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering, fence};
diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs
index 751a308a399..647f209e8bf 100644
--- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs
+++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+//@compile-flags:-Zmiri-deterministic-concurrency
 #![feature(core_intrinsics)]
 #![feature(custom_mir)]
 
diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs
index 16a23f595ee..f83d6c89fe5 100644
--- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs
+++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+//@compile-flags:-Zmiri-deterministic-concurrency
 use std::sync::atomic::Ordering::*;
 use std::sync::atomic::*;
 
diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs
index 7e00573146c..ee1bef7ba5c 100644
--- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs
+++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
+//@compile-flags:-Zmiri-deterministic-concurrency
 use std::sync::atomic::Ordering::*;
 use std::sync::atomic::*;
 
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs
index e76654806bb..720602d011e 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs
@@ -1,6 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags:-Zmiri-deterministic-concurrency
 // Two variants: the atomic store matches the size of the first or second atomic load.
 //@revisions: match_first_load match_second_load
 
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs
index 53016bab780..78bba173ed7 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs
@@ -1,6 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags:-Zmiri-deterministic-concurrency
 // Two revisions, depending on which access goes first.
 //@revisions: read_write write_read
 
diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs
index 545e354a037..808280a4b31 100644
--- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs
+++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs
@@ -1,6 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags:-Zmiri-deterministic-concurrency
 //@revisions: fst snd
 
 use std::sync::atomic::{AtomicU8, AtomicU16, Ordering};
diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.rs b/src/tools/miri/tests/fail/data_race/read_write_race.rs
index adf19dda9d3..2aadef36c5b 100644
--- a/src/tools/miri/tests/fail/data_race/read_write_race.rs
+++ b/src/tools/miri/tests/fail/data_race/read_write_race.rs
@@ -1,7 +1,5 @@
 // We want to control preemption here. Stacked borrows interferes by having its own accesses.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::thread::spawn;
 
diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs
index f411767f7b5..cca39bb002c 100644
--- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs
+++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::ptr::null_mut;
 use std::sync::atomic::{AtomicPtr, Ordering};
diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs
index c4f94380822..262c039e4ae 100644
--- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs
+++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.rs b/src/tools/miri/tests/fail/data_race/release_seq_race.rs
index f03ab3efa06..8aeb6ee6ef1 100644
--- a/src/tools/miri/tests/fail/data_race/release_seq_race.rs
+++ b/src/tools/miri/tests/fail/data_race/release_seq_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::{sleep, spawn};
diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs
index 88ae01b3ca1..f465160718f 100644
--- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs
+++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.rs b/src/tools/miri/tests/fail/data_race/rmw_race.rs
index d738caa1058..39588c15ec7 100644
--- a/src/tools/miri/tests/fail/data_race/rmw_race.rs
+++ b/src/tools/miri/tests/fail/data_race/rmw_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::thread::spawn;
diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
index 762a8e51f69..5138bcbf8f7 100644
--- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
+++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::thread;
 
diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.rs b/src/tools/miri/tests/fail/data_race/write_write_race.rs
index 993d8d25b4c..b1a6b08b4c8 100644
--- a/src/tools/miri/tests/fail/data_race/write_write_race.rs
+++ b/src/tools/miri/tests/fail/data_race/write_write_race.rs
@@ -1,7 +1,5 @@
-// We want to control preemption here.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::thread::spawn;
 
diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs
index 8070a7f4fc2..cd21b0a8fa6 100644
--- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs
+++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs
@@ -1,6 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows
-// Avoid accidental synchronization via address reuse inside `thread::spawn`.
-//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0
+// We want to control preemption here. Stacked borrows interferes by having its own accesses.
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows
 
 use std::ptr::null_mut;
 use std::sync::atomic::{AtomicPtr, Ordering};
diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs
index ffa0443ce50..0e916364169 100644
--- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs
+++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs
@@ -4,6 +4,6 @@ fn main() {
     }
 
     unsafe {
-        let _ = malloc(0); //~ ERROR: calling a function with ABI C using caller ABI Rust
+        let _ = malloc(0); //~ ERROR: calling a function with calling convention "C" using caller calling convention "Rust"
     };
 }
diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr
index bf1fbb7721f..78730182923 100644
--- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr
+++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function with ABI C using caller ABI Rust
+error: Undefined Behavior: calling a function with calling convention "C" using caller calling convention "Rust"
   --> tests/fail/function_calls/check_arg_abi.rs:LL:CC
    |
 LL |         let _ = malloc(0);
-   |                 ^^^^^^^^^ calling a function with ABI C using caller ABI Rust
+   |                 ^^^^^^^^^ calling a function with calling convention "C" using caller calling convention "Rust"
    |
    = 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/function_calls/check_callback_abi.rs b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
index 6a7a26710d1..177e38105e6 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.rs
@@ -9,7 +9,7 @@ fn main() {
         // Make sure we check the ABI when Miri itself invokes a function
         // as part of a shim implementation.
         std::intrinsics::catch_unwind(
-            //~^ ERROR: calling a function with calling convention C using calling convention Rust
+            //~^ ERROR: calling a function with calling convention "C" using calling convention "Rust"
             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
             std::ptr::null_mut(),
             |_, _| unreachable!(),
diff --git a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
index 6b0692e1c6e..20182ac9236 100644
--- a/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
+++ b/src/tools/miri/tests/fail/function_calls/check_callback_abi.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust"
   --> tests/fail/function_calls/check_callback_abi.rs:LL:CC
    |
 LL | /         std::intrinsics::catch_unwind(
@@ -7,7 +7,7 @@ LL | |             std::mem::transmute::<extern "C" fn(*mut u8), _>(try_fn),
 LL | |             std::ptr::null_mut(),
 LL | |             |_, _| unreachable!(),
 LL | |         );
-   | |_________^ calling a function with calling convention C using calling convention Rust
+   | |_________^ calling a function with calling convention "C" using calling convention "Rust"
    |
    = 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/function_calls/exported_symbol_abi_mismatch.cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr
index e4302ad1d3a..46a32d1487e 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function with calling convention Rust using calling convention C
+error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C"
   --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC
    |
 LL |             foo();
-   |             ^^^^^ calling a function with calling convention Rust using calling convention C
+   |             ^^^^^ calling a function with calling convention "Rust" using calling convention "C"
    |
    = 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/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr
index 9f40c48b338..38725289919 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function with calling convention Rust using calling convention C
+error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C"
   --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC
    |
 LL |         std::mem::transmute::<unsafe fn(), unsafe extern "C" fn()>(foo)();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "Rust" using calling convention "C"
    |
    = 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/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr
index e4302ad1d3a..46a32d1487e 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function with calling convention Rust using calling convention C
+error: Undefined Behavior: calling a function with calling convention "Rust" using calling convention "C"
   --> tests/fail/function_calls/exported_symbol_abi_mismatch.rs:LL:CC
    |
 LL |             foo();
-   |             ^^^^^ calling a function with calling convention Rust using calling convention C
+   |             ^^^^^ calling a function with calling convention "Rust" using calling convention "C"
    |
    = 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/function_calls/exported_symbol_abi_mismatch.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs
index 50a0e8e6ede..1950e162c07 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_abi_mismatch.rs
@@ -12,7 +12,7 @@ fn main() {
     #[cfg(fn_ptr)]
     unsafe {
         std::mem::transmute::<unsafe fn(), unsafe extern "C" fn()>(foo)();
-        //~[fn_ptr]^ ERROR: calling a function with calling convention Rust using calling convention C
+        //~[fn_ptr]^ ERROR: calling a function with calling convention "Rust" using calling convention "C"
     }
 
     // `Instance` caching should not suppress ABI check.
@@ -28,8 +28,8 @@ fn main() {
         }
         unsafe {
             foo();
-            //~[no_cache]^ ERROR: calling a function with calling convention Rust using calling convention C
-            //~[cache]| ERROR: calling a function with calling convention Rust using calling convention C
+            //~[no_cache]^ ERROR: calling a function with calling convention "Rust" using calling convention "C"
+            //~[cache]| ERROR: calling a function with calling convention "Rust" using calling convention "C"
         }
     }
 }
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
index b2a501db776..7cb2bf99678 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr
@@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
index b2a501db776..7cb2bf99678 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr
@@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
index 1382e9571f3..9d993786d57 100644
--- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
+++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs
@@ -1,5 +1,5 @@
 //@revisions: extern_block definition both
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
index f2d9933188d..37d3beefcd7 100644
--- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/function_pointers/cast_int_to_fn_ptr.rs:LL:CC
    |
 LL |     g(42)
-   |     ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
+   |     ^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
index c87ce321784..b7ed36f6428 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/intrinsics/ptr_offset_int_plus_int.rs:LL:CC
    |
 LL |         let _val = (1 as *mut u8).offset(1);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
index 78239d50137..29d9e1c64bd 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs:LL:CC
    |
 LL |         let _val = (1 as *mut u8).offset(ptr as isize);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/ptr_offset_out_of_bounds.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs
index 905fc678f6d..e44d398c998 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v = [0i8; 4];
     let x = &v as *const i8;
-    let x = unsafe { x.offset(5) }; //~ERROR: expected a pointer to 5 bytes of memory
+    let x = unsafe { x.offset(5) }; //~ERROR: is only 4 bytes from the end of the allocation
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr
index 4f6b45b897b..143fae8587b 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation
   --> tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC
    |
 LL |     let x = unsafe { x.offset(5) };
-   |                      ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation
+   |                      ^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation
    |
    = 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/ptr_offset_out_of_bounds_neg.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs
index bd1d5c064c0..5ad17373566 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs
@@ -1,6 +1,6 @@
 fn main() {
     let v = [0i8; 4];
     let x = &v as *const i8;
-    let x = unsafe { x.offset(-1) }; //~ERROR: expected a pointer to the end of 1 byte of memory
+    let x = unsafe { x.offset(-1) }; //~ERROR: is at the beginning of the allocation
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr
index 2dd4c943e86..14163d92404 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation
   --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC
    |
 LL |     let x = unsafe { x.offset(-1) };
-   |                      ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation
+   |                      ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation
    |
    = 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/ptr_offset_overflow.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
index 68394312232..6767b1f117a 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs
@@ -3,6 +3,6 @@
 fn main() {
     let v = [0i8; 4];
     let x = &v as *const i8;
-    let x = unsafe { x.offset(isize::MIN) }; //~ERROR: out-of-bounds pointer arithmetic
+    let x = unsafe { x.offset(isize::MIN) }; //~ERROR: in-bounds pointer arithmetic failed
     panic!("this should never print: {:?}", x);
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
index d03c9f870e2..af08bfb3c94 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation
   --> tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC
    |
 LL |     let x = unsafe { x.offset(isize::MIN) };
-   |                      ^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation
+   |                      ^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation
    |
    = 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/simd-gather.rs b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
index b8373952451..45a3dfa5772 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
+++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs
@@ -6,6 +6,6 @@ fn main() {
         let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18];
         let idxs = Simd::from_array([9, 3, 0, 17]);
         let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0));
-        //~^ERROR: expected a pointer to 1 byte of memory
+        //~^ERROR: attempting to access 1 byte
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
index ee1c9009610..e91d5d2185f 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
   --> tests/fail/intrinsics/simd-gather.rs:LL:CC
    |
 LL |         let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0));
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
    |
    = 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/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
index bb8c9dbe4c7..4e727edd624 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
+++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs
@@ -6,7 +6,7 @@ fn main() {
         let mut vec: Vec<i8> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
         let idxs = Simd::from_array([9, 3, 0, 17]);
         Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(
-            //~^ERROR: expected a pointer to 1 byte of memory
+            //~^ERROR: attempting to access 1 byte
             &mut vec,
             Mask::splat(true),
             idxs,
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
index aaacb94f458..56c8e7b38b6 100644
--- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
   --> tests/fail/intrinsics/simd-scatter.rs:LL:CC
    |
 LL | /         Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(
@@ -7,7 +7,7 @@ LL | |             &mut vec,
 LL | |             Mask::splat(true),
 LL | |             idxs,
 LL | |         );
-   | |_________^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
+   | |_________^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes
    |
    = 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/simd-select-bitmask-invalid.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs
deleted file mode 100644
index 409098ac3b5..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(core_intrinsics, repr_simd)]
-
-use std::intrinsics::simd::simd_select_bitmask;
-
-#[repr(simd)]
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone)]
-struct i32x2([i32; 2]);
-
-fn main() {
-    unsafe {
-        let x = i32x2([0, 1]);
-        simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits
-    }
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr
deleted file mode 100644
index 9acb51d8c5f..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits
-  --> tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC
-   |
-LL |         simd_select_bitmask(0b11111111u8, x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
index 6e0e0ca9f53..dd3246d8120 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
@@ -1,4 +1,4 @@
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
index 2c9bea1724d..ba96e595bee 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
@@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
index 0e8d3d08c12..3d355bad626 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
@@ -1,4 +1,4 @@
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
index 0634298a38f..7e1f4160cc0 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
@@ -7,7 +7,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs
index e313d9c11de..bd819362da4 100644
--- a/src/tools/miri/tests/fail/panic/abort_unwind.rs
+++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs
@@ -1,5 +1,5 @@
 //@error-in-other-file: the program aborted execution
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
index 3a63cb38ad0..e6668b09f66 100644
--- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr
+++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr
@@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs
index ddc75521eca..4d8f4cb6fb7 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.rs
+++ b/src/tools/miri/tests/fail/panic/double_panic.rs
@@ -1,4 +1,4 @@
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr
index 16e933be434..67f88955def 100644
--- a/src/tools/miri/tests/fail/panic/double_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/double_panic.stderr
@@ -14,7 +14,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.rs b/src/tools/miri/tests/fail/panic/panic_abort1.rs
index 7552c7b7e80..06cb673778a 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort1.rs
+++ b/src/tools/miri/tests/fail/panic/panic_abort1.rs
@@ -1,6 +1,6 @@
 //@error-in-other-file: the program aborted execution
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@compile-flags: -C panic=abort
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
index c950b2b4ea6..6d56874ebde 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr
@@ -4,13 +4,15 @@ panicking from libstd
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
 error: abnormal termination: the program aborted execution
-  --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |                 ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
-   = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC
+   = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.rs b/src/tools/miri/tests/fail/panic/panic_abort2.rs
index 624f9933545..c011b3ee7eb 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort2.rs
+++ b/src/tools/miri/tests/fail/panic/panic_abort2.rs
@@ -1,6 +1,6 @@
 //@error-in-other-file: the program aborted execution
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@compile-flags: -C panic=abort
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
index 9a9266ec493..dbb56f13f48 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr
@@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort2.rs:LL:CC:
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
 error: abnormal termination: the program aborted execution
-  --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |                 ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
-   = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC
+   = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.rs b/src/tools/miri/tests/fail/panic/panic_abort3.rs
index d1435b55946..911dc4a44ab 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort3.rs
+++ b/src/tools/miri/tests/fail/panic/panic_abort3.rs
@@ -1,6 +1,6 @@
 //@error-in-other-file: the program aborted execution
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@compile-flags: -C panic=abort
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
index f04a2b0f3f1..7f0564879e4 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr
@@ -4,13 +4,15 @@ panicking from libcore
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
 error: abnormal termination: the program aborted execution
-  --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |                 ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
-   = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC
+   = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.rs b/src/tools/miri/tests/fail/panic/panic_abort4.rs
index 54b9c9cbfdb..696fdff7422 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort4.rs
+++ b/src/tools/miri/tests/fail/panic/panic_abort4.rs
@@ -1,6 +1,6 @@
 //@error-in-other-file: the program aborted execution
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\); \}|core::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@compile-flags: -C panic=abort
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
index e71c4879ea3..ce6910b9933 100644
--- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr
+++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr
@@ -4,13 +4,15 @@ thread 'main' panicked at tests/fail/panic/panic_abort4.rs:LL:CC:
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
 error: abnormal termination: the program aborted execution
-  --> RUSTLIB/panic_abort/src/lib.rs:LL:CC
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |                 ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
-   = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
+   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
+   = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC
+   = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC
    = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr
index 62e3bd2e954..4e741fe8329 100644
--- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr
+++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/int_copy_looses_provenance3.rs:LL:CC
    |
 LL |     let _val = unsafe { *ptr };
-   |                         ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                         ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
index 6bc92fffd5a..370f9463b73 100644
--- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
+++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC
    |
 LL |     let x = *p;
-   |             ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |             ^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
index 7403f4382de..38e2e19009a 100644
--- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
+++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/provenance_transmute.rs:LL:CC
    |
 LL |         let _val = *left_ptr;
-   |                    ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^^^^^^^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/ptr_copy_loses_partial_provenance0.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr
index 5ed83951c60..5225ab32865 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs:LL:CC
    |
 LL |         let _val = *ptr;
-   |                    ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/ptr_copy_loses_partial_provenance1.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr
index 3675653cbe7..c17c98fa105 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs:LL:CC
    |
 LL |         let _val = *ptr;
-   |                    ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
index 1b6518612ef..78290d4ed63 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/ptr_int_unexposed.rs:LL:CC
    |
 LL |     assert_eq!(unsafe { *ptr }, 3);
-   |                         ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                         ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
index 84347ec7a11..ff73fbb9d1b 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/ptr_invalid.rs:LL:CC
    |
 LL |     let _val = unsafe { *xptr_invalid };
-   |                         ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                         ^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
index 3910bc4df4b..07556540f13 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/provenance/ptr_invalid_offset.rs:LL:CC
    |
 LL |     let _ = unsafe { roundtrip.offset(1) };
-   |                      ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                      ^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/ptr_swap_nonoverlapping.rs b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs
index 6f627c416b0..6119e8604b4 100644
--- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs
+++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs
@@ -1,6 +1,6 @@
 //! This is a regression test for <https://github.com/rust-lang/miri/issues/4188>: The precondition
 //! check in `ptr::swap_nonoverlapping` was incorrectly disabled in Miri.
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
index 80dd2f39b42..f57487e3ffe 100644
--- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
+++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
@@ -9,7 +9,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr
index 0fcb0faf497..e1d0e5780a0 100644
--- a/src/tools/miri/tests/fail/rc_as_ptr.stderr
+++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling
+error: Undefined Behavior: pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling
   --> tests/fail/rc_as_ptr.rs:LL:CC
    |
 LL |     assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling
    |
    = 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/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
index 92179644169..61fb9cd4e52 100644
--- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
+++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
   --> tests/fail/reading_half_a_pointer.rs:LL:CC
    |
 LL |         let _val = *x;
-   |                    ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
+   |                    ^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance)
    |
    = 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/backtrace/bad-backtrace-ptr.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
index 75f7aae9718..a398eb1ae0c 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs
@@ -4,6 +4,6 @@ extern "Rust" {
 
 fn main() {
     unsafe {
-        miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: got a null pointer
+        miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer
     }
 }
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
index 7ae9558fad7..126f41fbb0e 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
   --> tests/fail/shims/backtrace/bad-backtrace-ptr.rs:LL:CC
    |
 LL |         miri_resolve_frame(std::ptr::null_mut(), 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer
    |
    = 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/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
index a6ee7b40c34..6ff69554387 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
@@ -1,5 +1,4 @@
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags:-Zmiri-deterministic-concurrency
 use std::thread;
 
 #[derive(Copy, Clone)]
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
index 949f659e7e8..f46f13a39e7 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
@@ -1,6 +1,5 @@
 //! Make sure that a retag acts like a read for the data race model.
-// Avoid accidental synchronization via address reuse.
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags:-Zmiri-deterministic-concurrency
 #[derive(Copy, Clone)]
 struct SendPtr(*mut u8);
 
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
index 5f00dbf2573..952f9697fc7 100644
--- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs
@@ -1,4 +1,4 @@
-//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+//@error-in-other-file: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust"
 #![feature(explicit_tail_calls)]
 #![allow(incomplete_features)]
 
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
index 5061c9e8dc3..61ddea64472 100644
--- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function with calling convention C using calling convention Rust
+error: Undefined Behavior: calling a function with calling convention "C" using calling convention "Rust"
   --> RUSTLIB/core/src/ops/function.rs:LL:CC
    |
 LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention "C" using calling convention "Rust"
    |
    = 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/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs
index 465625c7572..31ae829a2de 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.rs
+++ b/src/tools/miri/tests/fail/terminate-terminator.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr
index f2548bf5cdb..d16119a30e6 100644
--- a/src/tools/miri/tests/fail/terminate-terminator.stderr
+++ b/src/tools/miri/tests/fail/terminate-terminator.stderr
@@ -13,7 +13,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr
deleted file mode 100644
index b9651e21ece..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: entering unreachable code
-  --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-   |
-LL |         std::hint::unreachable_unchecked();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs
deleted file mode 100644
index d3f272dfbf8..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-//@revisions: default uniq
-//@compile-flags: -Zmiri-tree-borrows
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
-
-//! This is NOT intended behavior.
-//! We should eventually find a solution so that the version with `Unique` passes too,
-//! otherwise `Unique` is more strict than `&mut`!
-
-#![feature(ptr_internals)]
-
-use core::ptr::{Unique, addr_of_mut};
-
-fn main() {
-    let mut data = 0u8;
-    let raw = addr_of_mut!(data);
-    unsafe {
-        raw_children_of_refmut_can_alias(&mut *raw);
-        raw_children_of_unique_can_alias(Unique::new_unchecked(raw));
-
-        // Ultimately the intended behavior is that both above tests would
-        // succeed.
-        std::hint::unreachable_unchecked();
-        //~[default]^ ERROR: entering unreachable code
-    }
-}
-
-unsafe fn raw_children_of_refmut_can_alias(x: &mut u8) {
-    let child1 = addr_of_mut!(*x);
-    let child2 = addr_of_mut!(*x);
-    // We create two raw aliases of `x`: they have the exact same
-    // tag and can be used interchangeably.
-    child1.write(1);
-    child2.write(2);
-    child1.write(1);
-    child2.write(2);
-}
-
-unsafe fn raw_children_of_unique_can_alias(x: Unique<u8>) {
-    let child1 = x.as_ptr();
-    let child2 = x.as_ptr();
-    // Under `-Zmiri-unique-is-unique`, `Unique` accidentally offers more guarantees
-    // than `&mut`. Not because it responds differently to accesses but because
-    // there is no easy way to obtain a copy with the same tag.
-    //
-    // The closest (non-hack) attempt is two calls to `as_ptr`.
-    // - Without `-Zmiri-unique-is-unique`, independent `as_ptr` calls return pointers
-    //   with the same tag that can thus be used interchangeably.
-    // - With the current implementation of `-Zmiri-unique-is-unique`, they return cousin
-    //   tags with permissions that do not tolerate aliasing.
-    // Eventually we should make such aliasing allowed in some situations
-    // (e.g. when there is no protector), which will probably involve
-    // introducing a new kind of permission.
-    child1.write(1);
-    child2.write(2);
-    //~[uniq]^ ERROR: /write access through .* is forbidden/
-    child1.write(1);
-    child2.write(2);
-}
diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr
deleted file mode 100644
index 83c506abb2d..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
-  --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-   |
-LL |     child2.write(2);
-   |     ^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
-   = help: the accessed tag <TAG> has state Disabled which forbids this child write access
-help: the accessed tag <TAG> was created here, in the initial state Reserved
-  --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-   |
-LL |     let child2 = x.as_ptr();
-   |                  ^^^^^^^^^^
-help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1]
-  --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-   |
-LL |     child1.write(1);
-   |     ^^^^^^^^^^^^^^^
-   = help: this transition corresponds to a loss of read and write permissions
-   = note: BACKTRACE (of the first span):
-   = note: inside `raw_children_of_unique_can_alias` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-note: inside `main`
-  --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
-   |
-LL |         raw_children_of_unique_can_alias(Unique::new_unchecked(raw));
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs
index 7af1a7636fa..bf963f6a8f7 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs
@@ -12,16 +12,16 @@ use std::cell::UnsafeCell;
 fn main() {
     unsafe {
         let n = &mut UnsafeCell::new(0u8);
-        name!(n.get(), "base");
+        name!(n as *mut _, "base");
         let x = &mut *(n as *mut UnsafeCell<_>);
-        name!(x.get(), "x");
-        let y = (&mut *n).get();
+        name!(x as *mut _, "x");
+        let y = (&mut *n) as *mut UnsafeCell<_> as *mut _;
         name!(y);
         write_second(x, y);
         unsafe fn write_second(x: &mut UnsafeCell<u8>, y: *mut u8) {
             let alloc_id = alloc_id!(x.get());
-            name!(x.get(), "callee:x");
-            name!(x.get()=>1, "caller:x");
+            name!(x as *mut _, "callee:x");
+            name!((x as *mut _)=>1, "caller:x");
             name!(y, "callee:y");
             name!(y, "caller:y");
             print_state!(alloc_id);
diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
index 03f79fe0a5d..10414df6a6a 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr
@@ -21,7 +21,7 @@ LL |             *y = 1;
 help: the accessed tag <TAG> was created here
   --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC
    |
-LL |         let y = (&mut *n).get();
+LL |         let y = (&mut *n) as *mut UnsafeCell<_> as *mut _;
    |                 ^^^^^^^^^
 help: the protected tag <TAG> was created here, in the initial state Reserved
   --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
index 73f227fee2f..024a14600b1 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
@@ -1,7 +1,7 @@
 // Illustrating a problematic interaction between Reserved, interior mutability,
 // and protectors, that makes spurious writes fail in the previous model of Tree Borrows.
 // As for all similar tests, we disable preemption so that the error message is deterministic.
-//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-tree-borrows -Zmiri-deterministic-concurrency
 //
 // One revision without spurious read (default source code) and one with spurious read.
 // Both are expected to be UB. Both revisions are expected to have the *same* error
diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs
index 50ef0ceef91..4ca0fb94338 100644
--- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs
@@ -1,8 +1,8 @@
 // We ensure a deterministic execution.
 // Note that we are *also* using barriers: the barriers enforce the
-// specific interleaving of operations that we want, but only the preemption
-// rate guarantees that the error message is also deterministic.
-//@compile-flags: -Zmiri-preemption-rate=0
+// specific interleaving of operations that we want, but we need to disable
+// preemption to ensure that the error message is also deterministic.
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@compile-flags: -Zmiri-tree-borrows
 
 use std::sync::{Arc, Barrier};
diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.rs b/src/tools/miri/tests/fail/tree_borrows/unique.rs
deleted file mode 100644
index 0844dd21a59..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/unique.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@revisions: default uniq
-//@compile-flags: -Zmiri-tree-borrows
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
-
-// A pattern that detects if `Unique` is treated as exclusive or not:
-// activate the pointer behind a `Unique` then do a read that is parent
-// iff `Unique` was specially reborrowed.
-
-#![feature(ptr_internals)]
-use core::ptr::Unique;
-
-fn main() {
-    let mut data = 0u8;
-    let refmut = &mut data;
-    let rawptr = refmut as *mut u8;
-
-    unsafe {
-        let uniq = Unique::new_unchecked(rawptr);
-        *uniq.as_ptr() = 1; // activation
-        let _maybe_parent = *rawptr; // maybe becomes Frozen
-        *uniq.as_ptr() = 2;
-        //~[uniq]^ ERROR: /write access through .* is forbidden/
-        let _definitely_parent = data; // definitely Frozen by now
-        *uniq.as_ptr() = 3;
-        //~[default]^ ERROR: /write access through .* is forbidden/
-    }
-}
diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr
deleted file mode 100644
index 4ecff3ea0e1..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         *uniq.as_ptr() = 2;
-   |         ^^^^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
-   = help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
-   = help: the conflicting tag <TAG> has state Frozen which forbids this child write access
-help: the accessed tag <TAG> was created here
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         *uniq.as_ptr() = 2;
-   |          ^^^^^^^^^^^^^
-help: the conflicting tag <TAG> was created here, in the initial state Reserved
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         let uniq = Unique::new_unchecked(rawptr);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         *uniq.as_ptr() = 1; // activation
-   |         ^^^^^^^^^^^^^^^^^^
-   = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
-help: the conflicting tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         let _maybe_parent = *rawptr; // maybe becomes Frozen
-   |                             ^^^^^^^
-   = help: this transition corresponds to a loss of write permissions
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs
index 465e07c8db4..f0fbcfd8867 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.rs
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs
@@ -1,5 +1,5 @@
 //@error-in-other-file: aborted execution
-//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
+//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
 //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
 //@normalize-stderr-test: "\n +at [^\n]+" -> ""
diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
index 7b9a4383fc4..222d4fb2866 100644
--- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr
+++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr
@@ -11,7 +11,7 @@ thread caused non-unwinding panic. aborting.
 error: abnormal termination: the program aborted execution
   --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
    |
-LL |     ABORT();
+LL | ABORT()
    | ^ the program aborted execution
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
deleted file mode 100644
index a437ca34258..00000000000
--- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: Undefined Behavior: Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-  --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-   |
-LL |             std::intrinsics::atomic_load_relaxed(hi);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte atomic store on thread `unnamed-ID` and (2) 2-byte atomic load on thread `unnamed-ID` at ALLOC. (2) just happened here
-   |
-help: and (1) occurred earlier here
-  --> tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-   |
-LL |         x.store(1, Relaxed);
-   |         ^^^^^^^^^^^^^^^^^^^
-   = help: overlapping unsynchronized atomic accesses must use the same access size
-   = help: see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
-   = note: inside closure at tests/fail/weak_memory/racing_mixed_size.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
index 79c97a5b752..b4b4b084987 100644
--- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
+++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule
 
 // Tests showing weak memory behaviours are exhibited. All tests
 // return true when the desired behaviour is seen.
diff --git a/src/tools/miri/tests/fail/zst_local_oob.rs b/src/tools/miri/tests/fail/zst_local_oob.rs
index ab48b7d330b..2bf184c72ba 100644
--- a/src/tools/miri/tests/fail/zst_local_oob.rs
+++ b/src/tools/miri/tests/fail/zst_local_oob.rs
@@ -1,5 +1,5 @@
 fn main() {
     // make sure ZST locals cannot be accessed
     let x = &() as *const () as *const i8;
-    let _val = unsafe { *x }; //~ ERROR: expected a pointer to 1 byte of memory
+    let _val = unsafe { *x }; //~ ERROR: attempting to access 1 byte
 }
diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr
index 26911948eff..e9423096226 100644
--- a/src/tools/miri/tests/fail/zst_local_oob.stderr
+++ b/src/tools/miri/tests/fail/zst_local_oob.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
+error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
   --> tests/fail/zst_local_oob.rs:LL:CC
    |
 LL |     let _val = unsafe { *x };
-   |                         ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
+   |                         ^^ memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes
    |
    = 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/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/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs
index becb90eb923..a28f08c3bb1 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs
@@ -1,5 +1,5 @@
 //@only-target: darwin
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::time::{Duration, Instant};
 use std::{io, ptr, thread};
diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
index c9c9dc5dfd2..91cf24a944a 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency
 //@ignore-target: windows # No libc env support on Windows
 
 use std::ffi::CStr;
diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs
index 38a0bf58148..b10ded8e4d0 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs
@@ -1,5 +1,5 @@
 //@only-target: freebsd
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-isolation
+//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-isolation
 
 use std::mem::{self, MaybeUninit};
 use std::ptr::{self, addr_of};
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs
index fe2d20bb76f..41b26c84393 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs
@@ -1,6 +1,6 @@
 //@only-target: windows # Uses win32 api functions
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::os::windows::io::IntoRawHandle;
 use std::thread;
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs
index 6853395686a..0a1fb117507 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs
@@ -1,6 +1,6 @@
 //@only-target: windows # Uses win32 api functions
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::ptr::null_mut;
 use std::thread;
diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
index 2796541a3d7..acd9270ad16 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs
@@ -1,6 +1,6 @@
 //@only-target: windows # Uses win32 api functions
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::os::windows::io::IntoRawHandle;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
index 825e1355848..54ebfa9d198 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
@@ -1,6 +1,6 @@
 //@only-target: linux android illumos
 // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::convert::TryInto;
 use std::thread;
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
index 30e1bbb8fa1..56d215d0ed6 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
@@ -1,6 +1,6 @@
 //@only-target: linux android illumos
 // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
 #![allow(static_mut_refs)]
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
index d6072c2569e..05f6c870c3d 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
@@ -1,6 +1,6 @@
 //@ignore-target: windows # No libc pipe on Windows
 // test_race depends on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 use std::thread;
 fn main() {
     test_pipe();
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
index 9163fd3d06f..9e48410f704 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
@@ -1,6 +1,6 @@
 //@ignore-target: windows # No libc socketpair on Windows
 // test_race depends on a deterministic schedule.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
 #![allow(static_mut_refs)]
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
index fa11b5b1299..25594466294 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
@@ -1,6 +1,6 @@
 //@ignore-target: windows # No pthreads on Windows
 // We use `yield` to test specific interleavings, so disable automatic preemption.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 #![feature(sync_unsafe_cell)]
 
 use std::cell::SyncUnsafeCell;
diff --git a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs b/src/tools/miri/tests/pass/both_borrows/2phase.rs
index fb4ba605837..7a3962a7c1a 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs
+++ b/src/tools/miri/tests/pass/both_borrows/2phase.rs
@@ -1,5 +1,5 @@
-// FIXME: this miscompiles with optimizations, see <https://github.com/rust-lang/rust/issues/132898>.
-//@compile-flags: -Zmir-opt-level=0
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 
 trait S: Sized {
     fn tpb(&mut self, _s: Self) {}
@@ -31,9 +31,9 @@ fn two_phase3(b: bool) {
     ));
 }
 
-#[allow(unreachable_code)]
 fn two_phase_raw() {
     let x: &mut Vec<i32> = &mut vec![];
+    #[allow(unreachable_code)] // The `push` itself never gets reached.
     x.push({
         // Unfortunately this does not trigger the problem of creating a
         // raw ponter from a pointer that had a two-phase borrow derived from
@@ -59,52 +59,12 @@ fn two_phase_overlapping2() {
     x.add_assign(x + *l);
 }
 
-fn with_interior_mutability() {
-    use std::cell::Cell;
-
-    trait Thing: Sized {
-        fn do_the_thing(&mut self, _s: i32) {}
-    }
-
-    impl<T> Thing for Cell<T> {}
-
-    let mut x = Cell::new(1);
-    let l = &x;
-
-    x.do_the_thing({
-        x.set(3);
-        l.set(4);
-        x.get() + l.get()
-    });
-}
-
-// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it.
-// Tree Borrows rejects it.
-fn aliasing_violation() {
-    struct Foo(u64);
-    impl Foo {
-        fn add(&mut self, n: u64) -> u64 {
-            self.0 + n
-        }
-    }
-
-    let mut f = Foo(0);
-    let alias = &mut f.0 as *mut u64;
-    let res = f.add(unsafe {
-        *alias = 42;
-        0
-    });
-    assert_eq!(res, 42);
-}
-
 fn main() {
     two_phase1();
     two_phase2();
     two_phase3(false);
     two_phase3(true);
     two_phase_raw();
-    with_interior_mutability();
     two_phase_overlapping1();
     two_phase_overlapping2();
-    aliasing_violation();
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
index 4261f411eea..c76e7f2eebd 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
+++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
@@ -1,17 +1,17 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(allocator_api)]
 use std::ptr;
 
-// Test various stacked-borrows-related things.
+// Test various aliasing-model-related things.
 fn main() {
     read_does_not_invalidate1();
     read_does_not_invalidate2();
     mut_raw_then_mut_shr();
     mut_shr_then_mut_raw();
     mut_raw_mut();
-    mut_raw_mut2();
     partially_invalidate_mut();
     drop_after_sharing();
-    // direct_mut_to_const_raw();
     two_raw();
     shr_and_raw();
     disjoint_mutable_subborrows();
@@ -97,18 +97,6 @@ fn mut_raw_mut() {
     assert_eq!(x, 4);
 }
 
-// A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows.
-// It's kind of an accident that we accept it in Stacked Borrows...
-fn mut_raw_mut2() {
-    unsafe {
-        let mut root = 0;
-        let to = &mut root as *mut i32;
-        *to = 0;
-        let _val = root;
-        *to = 0;
-    }
-}
-
 fn partially_invalidate_mut() {
     let data = &mut (0u8, 0u8);
     let reborrow = &mut *data as *mut (u8, u8);
@@ -124,15 +112,6 @@ fn drop_after_sharing() {
     let _len = x.len();
 }
 
-// Make sure that coercing &mut T to *const T produces a writeable pointer.
-// TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
-/*fn direct_mut_to_const_raw() {
-    let x = &mut 0;
-    let y: *const i32 = x;
-    unsafe { *(y as *mut i32) = 1; }
-    assert_eq!(*x, 1);
-}*/
-
 // Make sure that we can create two raw pointers from a mutable reference and use them both.
 fn two_raw() {
     unsafe {
@@ -178,7 +157,7 @@ fn disjoint_mutable_subborrows() {
     let b = unsafe { borrow_field_b(ptr) };
     b.push(4);
     a.push_str(" world");
-    eprintln!("{:?} {:?}", a, b);
+    assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#);
 }
 
 fn raw_ref_to_part() {
@@ -243,7 +222,7 @@ fn not_unpin_not_protected() {
     pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned);
 
     fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-        // `f` may mutate, but it may not deallocate!
+        // `f` is allowed to deallocate `x`.
         f(x)
     }
 
diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs
index e86cb3711ac..f095e215e00 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
+++ b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs
@@ -1,3 +1,5 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![allow(dangerous_implicit_autorefs)]
 
 use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
@@ -14,6 +16,7 @@ fn main() {
     ref_protector();
     ref_mut_protector();
     rust_issue_68303();
+    two_phase();
 }
 
 fn aliasing_mut_and_shr() {
@@ -102,7 +105,14 @@ fn unsafe_cell_invalidate() {
     let ref1 = unsafe { &mut *raw1 };
     let raw2 = ref1 as *mut _;
     // Now the borrow stack is: raw1, ref2, raw2.
-    // So using raw1 invalidates raw2.
+    //
+    // For TB, the tree is
+    //
+    // Act x
+    // Res `- raw1
+    // Res    `- ref1, raw2
+    //
+    // Either way, using raw1 invalidates raw2.
     f(unsafe { mem::transmute(raw2) }, raw1);
 }
 
@@ -138,7 +148,7 @@ fn refcell_basic() {
     }
 }
 
-// Adding a Stacked Borrows protector for `Ref` would break this
+// Adding a protector for `Ref` would break this
 fn ref_protector() {
     fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
         // `r` has a shared reference, it is passed in as argument and hence
@@ -174,3 +184,27 @@ fn rust_issue_68303() {
     assert!(optional.is_some());
     *handle = true;
 }
+
+fn two_phase() {
+    use std::cell::Cell;
+
+    trait Thing: Sized {
+        fn do_the_thing(&mut self, _s: i32) {}
+    }
+
+    impl<T> Thing for Cell<T> {}
+
+    let mut x = Cell::new(1);
+    let l = &x;
+
+    x.do_the_thing({
+        // In TB terms:
+        // Several Foreign accesses (both Reads and Writes) to the location
+        // being reborrowed. Reserved + unprotected + interior mut
+        // makes the pointer immune to everything as long as all accesses
+        // are child accesses to its parent pointer x.
+        x.set(3);
+        l.set(4);
+        x.get() + l.get()
+    });
+}
diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs
index d16de0ae8e2..d5dd1deb2d9 100644
--- a/src/tools/miri/tests/pass/concurrency/data_race.rs
+++ b/src/tools/miri/tests/pass/concurrency/data_race.rs
@@ -1,4 +1,5 @@
-//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0
+// This tests carefully crafted schedules to ensure they are not considered races.
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::sync::atomic::*;
 use std::thread::{self, spawn};
diff --git a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs
index 354a4bef932..ecc4ca59bd1 100644
--- a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs
+++ b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs
@@ -1,6 +1,6 @@
 //@compile-flags: -Zmiri-disable-data-race-detector
 // Avoid non-determinism
-//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::thread::spawn;
 
diff --git a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs
index 44b16e1ac74..4361f1da924 100644
--- a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs
+++ b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs
@@ -1,5 +1,5 @@
 // This specifically tests behavior *without* preemption.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::cell::Cell;
 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs
index 91c67b215a1..a92359758da 100644
--- a/src/tools/miri/tests/pass/concurrency/sync.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync.rs
@@ -1,7 +1,7 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
 // We use `yield` to test specific interleavings, so disable automatic preemption.
-//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency
 
 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
 use std::thread;
diff --git a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs
index c6cff038f81..bea8f87243a 100644
--- a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs
+++ b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs
@@ -1,5 +1,5 @@
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 use std::sync::{Arc, Condvar, Mutex, RwLock};
 use std::thread;
diff --git a/src/tools/miri/tests/pass/coroutine.rs b/src/tools/miri/tests/pass/coroutine.rs
index 9ec9b1fc5bc..96b60b515cb 100644
--- a/src/tools/miri/tests/pass/coroutine.rs
+++ b/src/tools/miri/tests/pass/coroutine.rs
@@ -183,18 +183,18 @@ fn basic() {
 
 fn smoke_resume_arg() {
     fn drain<G: Coroutine<R, Yield = Y> + Unpin, R, Y>(
-        gen: &mut G,
+        gen_: &mut G,
         inout: Vec<(R, CoroutineState<Y, G::Return>)>,
     ) where
         Y: Debug + PartialEq,
         G::Return: Debug + PartialEq,
     {
-        let mut gen = Pin::new(gen);
+        let mut gen_ = Pin::new(gen_);
 
         for (input, out) in inout {
-            assert_eq!(gen.as_mut().resume(input), out);
+            assert_eq!(gen_.as_mut().resume(input), out);
             // Test if the coroutine is valid (according to type invariants).
-            let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) };
+            let _ = unsafe { ManuallyDrop::new(ptr::read(gen_.as_mut().get_unchecked_mut())) };
         }
     }
 
diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
index 89289a25d50..913c3cde272 100644
--- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
+++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs
@@ -33,20 +33,24 @@ fn main() {
     assert_eq!(intrinsics::likely(false), false);
     assert_eq!(intrinsics::unlikely(true), true);
 
-    let mut saw_true = false;
-    let mut saw_false = false;
+    // Skip this test when we use the fallback bodies, as that one is deterministic.
+    // (CI sets `--cfg force_intrinsic_fallback` together with `-Zmiri-force-intrinsic-fallback`.)
+    if !cfg!(force_intrinsic_fallback) {
+        let mut saw_true = false;
+        let mut saw_false = false;
 
-    for _ in 0..50 {
-        if intrinsics::is_val_statically_known(0) {
-            saw_true = true;
-        } else {
-            saw_false = true;
+        for _ in 0..50 {
+            if intrinsics::is_val_statically_known(0) {
+                saw_true = true;
+            } else {
+                saw_false = true;
+            }
         }
+        assert!(
+            saw_true && saw_false,
+            "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
+        );
     }
-    assert!(
-        saw_true && saw_false,
-        "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
-    );
 
     intrinsics::forget(Bomb);
 
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index cc753dac215..e14ce51f35a 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -331,6 +331,19 @@ fn simd_mask() {
         );
         assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1]));
         assert_eq!(selected2, selected1);
+        // Non-zero "padding" (the extra bits) is also allowed.
+        let selected1 = simd_select_bitmask::<u8, _>(
+            if cfg!(target_endian = "little") { 0b11111000 } else { 0b11110001 },
+            i32x4::splat(1), // yes
+            i32x4::splat(0), // no
+        );
+        let selected2 = simd_select_bitmask::<[u8; 1], _>(
+            if cfg!(target_endian = "little") { [0b11111000] } else { [0b11110001] },
+            i32x4::splat(1), // yes
+            i32x4::splat(0), // no
+        );
+        assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1]));
+        assert_eq!(selected2, selected1);
     }
 
     // Non-power-of-2 multi-byte mask.
diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.rs b/src/tools/miri/tests/pass/panic/concurrent-panic.rs
index e804df90977..4bf645960f7 100644
--- a/src/tools/miri/tests/pass/panic/concurrent-panic.rs
+++ b/src/tools/miri/tests/pass/panic/concurrent-panic.rs
@@ -1,5 +1,5 @@
 // We are making scheduler assumptions here.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 
 //! Cause a panic in one thread while another thread is unwinding. This checks
 //! that separate threads have their own panicking state.
diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs
index 655b29674e3..31e59c4a41c 100644
--- a/src/tools/miri/tests/pass/shims/env/var.rs
+++ b/src/tools/miri/tests/pass/shims/env/var.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 use std::{env, thread};
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
index 47f086f7340..48633c0a7fe 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
@@ -2,7 +2,7 @@
 //@only-target: x86_64 i686
 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f
 
-#![feature(avx512_target_feature, stdarch_x86_avx512)]
+#![feature(stdarch_x86_avx512)]
 
 use core::mem::transmute;
 #[cfg(target_arch = "x86")]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
index db593063890..0ec2f679d80 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
@@ -2,7 +2,6 @@
 //@only-target: x86_64 i686
 //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
 
-#![feature(avx512_target_feature)]
 #![feature(stdarch_x86_avx512)]
 
 #[cfg(target_arch = "x86")]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
index 882b5e3f795..b58d68e2ef9 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
@@ -6,7 +6,6 @@
 // be interpreted as integers; signedness does not make sense for them, but
 // __mXXXi happens to be defined in terms of signed integers.
 #![allow(overflowing_literals)]
-#![feature(avx512_target_feature)]
 #![feature(stdarch_x86_avx512)]
 
 #[cfg(target_arch = "x86")]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs
index 7aaf9c2624f..731d8b57763 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse2.rs
@@ -1,5 +1,6 @@
 // We're testing x86 target specific features
 //@only-target: x86_64 i686
+#![allow(unnecessary_transmutes)]
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
index 68964728e4e..c7c9eb5e395 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
@@ -8,7 +8,6 @@
 // be interpreted as integers; signedness does not make sense for them, but
 // __mXXXi happens to be defined in terms of signed integers.
 #![allow(overflowing_literals)]
-#![feature(avx512_target_feature)]
 #![feature(stdarch_x86_avx512)]
 
 #[cfg(target_arch = "x86")]
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr
deleted file mode 100644
index 8ee4e25dbef..00000000000
--- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr
+++ /dev/null
@@ -1 +0,0 @@
-"hello world" [0, 1, 2, 4]
diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs
index 72e360fe19a..72e360fe19a 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs
index 8a05fca3f31..8a05fca3f31 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs
index 469122095e5..469122095e5 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr
index bcb7a65e90f..8ca3c6c618e 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr
+++ b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr
@@ -1,5 +1,5 @@
 warning: integer-to-pointer cast
-  --> tests/pass/stacked-borrows/issue-miri-2389.rs:LL:CC
+  --> tests/pass/stacked_borrows/issue-miri-2389.rs:LL:CC
    |
 LL |         let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i32>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
@@ -10,5 +10,5 @@ LL |         let wildcard = &root0 as *const Cell<i32> as usize as *const Cell<i
    = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
    = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning
    = note: BACKTRACE:
-   = note: inside `main` at tests/pass/stacked-borrows/issue-miri-2389.rs:LL:CC
+   = note: inside `main` at tests/pass/stacked_borrows/issue-miri-2389.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs b/src/tools/miri/tests/pass/stacked_borrows/no_field_retagging.rs
index 507df068a7e..507df068a7e 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/no_field_retagging.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/no_field_retagging.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/non_scalar_field_retagging.rs b/src/tools/miri/tests/pass/stacked_borrows/non_scalar_field_retagging.rs
index 92d8f3237d0..92d8f3237d0 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/non_scalar_field_retagging.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/non_scalar_field_retagging.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.rs
index e507f49b955..e507f49b955 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout
index 296339e7384..296339e7384 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stack-printing.stdout
+++ b/src/tools/miri/tests/pass/stacked_borrows/stack-printing.stdout
diff --git a/src/tools/miri/tests/pass/stacked_borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/stacked_borrows/stacked-borrows.rs
new file mode 100644
index 00000000000..e68a5d8ffe7
--- /dev/null
+++ b/src/tools/miri/tests/pass/stacked_borrows/stacked-borrows.rs
@@ -0,0 +1,50 @@
+// FIXME: this miscompiles with optimizations, see <https://github.com/rust-lang/rust/issues/132898>.
+//@compile-flags: -Zmir-opt-level=0
+
+// Test various stacked-borrows-specific things
+// (i.e., these do not work the same under TB).
+fn main() {
+    mut_raw_mut2();
+    // direct_mut_to_const_raw();
+    two_phase_aliasing_violation();
+}
+
+// A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows.
+// It's kind of an accident that we accept it in Stacked Borrows...
+fn mut_raw_mut2() {
+    unsafe {
+        let mut root = 0;
+        let to = &mut root as *mut i32;
+        *to = 0;
+        let _val = root;
+        *to = 0;
+    }
+}
+
+// Make sure that coercing &mut T to *const T produces a writeable pointer.
+// TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
+/*fn direct_mut_to_const_raw() {
+    let x = &mut 0;
+    let y: *const i32 = x;
+    unsafe { *(y as *mut i32) = 1; }
+    assert_eq!(*x, 1);
+}*/
+
+// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it.
+// Tree Borrows rejects it.
+fn two_phase_aliasing_violation() {
+    struct Foo(u64);
+    impl Foo {
+        fn add(&mut self, n: u64) -> u64 {
+            self.0 + n
+        }
+    }
+
+    let mut f = Foo(0);
+    let alias = &mut f.0 as *mut u64;
+    let res = f.add(unsafe {
+        *alias = 42;
+        0
+    });
+    assert_eq!(res, 42);
+}
diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs
index b0f53283cda..b0f53283cda 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs
diff --git a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs
index 4faf6004ad6..4faf6004ad6 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs
+++ b/src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs
diff --git a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs
deleted file mode 100644
index af52f53791a..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@compile-flags: -Zmiri-tree-borrows
-
-// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs,
-// this is the opposite situation: the Write is not problematic because
-// the Protector has not yet been added and the Reserved has interior
-// mutability.
-use core::cell::Cell;
-
-trait Thing: Sized {
-    fn do_the_thing(&mut self, _s: i32) {}
-}
-impl<T> Thing for Cell<T> {}
-
-fn main() {
-    let mut x = Cell::new(1);
-    let l = &x;
-
-    x.do_the_thing({
-        // Several Foreign accesses (both Reads and Writes) to the location
-        // being reborrowed. Reserved + unprotected + interior mut
-        // makes the pointer immune to everything as long as all accesses
-        // are child accesses to its parent pointer x.
-        x.set(3);
-        l.set(4);
-        x.get() + l.get()
-    });
-}
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs
index 3269acb5119..019ea369811 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs
@@ -6,16 +6,16 @@ mod utils;
 
 use std::cell::UnsafeCell;
 
-// UnsafeCells use the parent tag, so it is possible to use them with
+// UnsafeCells use the `Cell` state, so it is possible to use them with
 // few restrictions when only among themselves.
 fn main() {
     unsafe {
         let data = &mut UnsafeCell::new(0u8);
-        name!(data.get(), "data");
+        name!(data as *mut _, "data");
         let x = &*data;
-        name!(x.get(), "x");
+        name!(x as *const _, "x");
         let y = &*data;
-        name!(y.get(), "y");
+        name!(y as *const _, "y");
         let alloc_id = alloc_id!(data.get());
         print_state!(alloc_id);
         // y and x tolerate alternating Writes
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
index d13e9ad0215..75a30c9a083 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
@@ -2,11 +2,15 @@
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..   1
 | Act |    └─┬──<TAG=root of the allocation>
-| ReIM|      └────<TAG=data, x, y>
+| ReIM|      └─┬──<TAG=data>
+| Cel |        ├────<TAG=x>
+| Cel |        └────<TAG=y>
 ──────────────────────────────────────────────────
 ──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
 0..   1
 | Act |    └─┬──<TAG=root of the allocation>
-| Act |      └────<TAG=data, x, y>
+| Act |      └─┬──<TAG=data>
+| Cel |        ├────<TAG=x>
+| Cel |        └────<TAG=y>
 ──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs
new file mode 100644
index 00000000000..adf2f4e845b
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs
@@ -0,0 +1,35 @@
+//@compile-flags: -Zmiri-tree-borrows
+#![feature(box_as_ptr)]
+#[path = "../../utils/mod.rs"]
+#[macro_use]
+mod utils;
+
+use std::cell::UnsafeCell;
+
+pub fn main() {
+    let cell = UnsafeCell::new(42);
+    let box1 = Box::new(cell);
+
+    unsafe {
+        let ptr1: *mut UnsafeCell<i32> = Box::into_raw(box1);
+        name!(ptr1);
+
+        let mut box2 = Box::from_raw(ptr1);
+        // `ptr2` will be a descendant of `ptr1`.
+        let ptr2: *mut UnsafeCell<i32> = Box::as_mut_ptr(&mut box2);
+        name!(ptr2);
+
+        // We perform a write through `x`.
+        // Because `ptr1` is ReservedIM, a child write will make it transition to Active.
+        // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it.
+        let x = (*ptr1).get();
+        *x = 1;
+
+        // We can still read from `ptr2`.
+        let val = *(*ptr2).get();
+        assert_eq!(val, 1);
+
+        let alloc_id = alloc_id!(ptr1);
+        print_state!(alloc_id);
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr
index 7942e9884f4..5dbfff718b1 100644
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr
@@ -1,8 +1,7 @@
 ──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
-0..   2
+0..   4
 | Act |    └─┬──<TAG=root of the allocation>
-|-----|      └─┬──<TAG=base.as_ptr(), base.as_ptr()>
-|-----|        └─┬──<TAG=raw_parts.0>
-|-----|          └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
+| Act |      └─┬──<TAG=ptr1>
+| ReIM|        └────<TAG=ptr2>
 ──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs
deleted file mode 100644
index 6dde593d2cf..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-//@revisions: default uniq
-//@compile-flags: -Zmiri-tree-borrows
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
-#![allow(dangerous_implicit_autorefs)]
-use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
-use std::mem::{self, MaybeUninit};
-
-fn main() {
-    aliasing_mut_and_shr();
-    aliasing_frz_and_shr();
-    into_interior_mutability();
-    unsafe_cell_2phase();
-    unsafe_cell_deallocate();
-    unsafe_cell_invalidate();
-    refcell_basic();
-    ref_protector();
-    ref_mut_protector();
-    rust_issue_68303();
-}
-
-fn aliasing_mut_and_shr() {
-    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
-        *aliasing += 4;
-        let _escape_to_raw = rc as *const _;
-        *aliasing += 4;
-        let _shr = &*rc;
-        *aliasing += 4;
-        // also turning this into a frozen ref now must work
-        let aliasing = &*aliasing;
-        let _val = *aliasing;
-        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
-        let _val = *aliasing;
-        let _shr = &*rc; // this must NOT unfreeze
-        let _val = *aliasing;
-    }
-
-    let rc = RefCell::new(23);
-    let mut bmut = rc.borrow_mut();
-    inner(&rc, &mut *bmut);
-    drop(bmut);
-    assert_eq!(*rc.borrow(), 23 + 12);
-}
-
-fn aliasing_frz_and_shr() {
-    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
-        let _val = *aliasing;
-        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
-        let _val = *aliasing;
-        let _shr = &*rc; // this must NOT unfreeze
-        let _val = *aliasing;
-    }
-
-    let rc = RefCell::new(23);
-    let bshr = rc.borrow();
-    inner(&rc, &*bshr);
-    assert_eq!(*rc.borrow(), 23);
-}
-
-// Getting a pointer into a union with interior mutability used to be tricky
-// business (https://github.com/rust-lang/miri/issues/615), but it should work
-// now.
-fn into_interior_mutability() {
-    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
-    x.as_ptr();
-    x.write((Cell::new(0), 1));
-    let ptr = unsafe { x.assume_init_ref() };
-    assert_eq!(ptr.1, 1);
-}
-
-// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
-// invalidate aliases.
-fn unsafe_cell_2phase() {
-    unsafe {
-        let x = &UnsafeCell::new(vec![]);
-        let x2 = &*x;
-        (*x.get()).push(0);
-        let _val = (*x2.get()).get(0);
-    }
-}
-
-/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call.
-/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.)
-fn unsafe_cell_deallocate() {
-    fn f(x: &UnsafeCell<i32>) {
-        let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) };
-        drop(b)
-    }
-
-    let b = Box::new(0i32);
-    f(unsafe { mem::transmute(Box::into_raw(b)) });
-}
-
-/// As a side-effect of the above, we also allow this -- at least for now.
-fn unsafe_cell_invalidate() {
-    fn f(_x: &UnsafeCell<i32>, y: *mut i32) {
-        // Writing to y invalidates x, but that is okay.
-        unsafe {
-            *y += 1;
-        }
-    }
-
-    let mut x = 0i32;
-    let raw1 = &mut x as *mut _;
-    let ref1 = unsafe { &mut *raw1 };
-    let raw2 = ref1 as *mut _;
-    // Now the borrow stack is: raw1, ref2, raw2.
-    // So using raw1 invalidates raw2.
-    f(unsafe { mem::transmute(raw2) }, raw1);
-}
-
-fn refcell_basic() {
-    let c = RefCell::new(42);
-    {
-        let s1 = c.borrow();
-        let _x: i32 = *s1;
-        let s2 = c.borrow();
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-    }
-    {
-        let mut m = c.borrow_mut();
-        let _z: i32 = *m;
-        {
-            let s: &i32 = &*m;
-            let _x = *s;
-        }
-        *m = 23;
-        let _z: i32 = *m;
-    }
-    {
-        let s1 = c.borrow();
-        let _x: i32 = *s1;
-        let s2 = c.borrow();
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-    }
-}
-
-// Adding a Stacked Borrows protector for `Ref` would break this
-fn ref_protector() {
-    fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
-        // `r` has a shared reference, it is passed in as argument and hence
-        // a protector is added that marks this memory as read-only for the entire
-        // duration of this function.
-        drop(r);
-        // *oops* here we can mutate that memory.
-        *rc.borrow_mut() = 2;
-    }
-
-    let rc = RefCell::new(0);
-    break_it(&rc, rc.borrow())
-}
-
-fn ref_mut_protector() {
-    fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) {
-        // `r` has a shared reference, it is passed in as argument and hence
-        // a protector is added that marks this memory as inaccessible for the entire
-        // duration of this function
-        drop(r);
-        // *oops* here we can mutate that memory.
-        *rc.borrow_mut() = 2;
-    }
-
-    let rc = RefCell::new(0);
-    break_it(&rc, rc.borrow_mut())
-}
-
-/// Make sure we do not have bad enum layout optimizations.
-fn rust_issue_68303() {
-    let optional = Some(RefCell::new(false));
-    let mut handle = optional.as_ref().unwrap().borrow_mut();
-    assert!(optional.is_some());
-    *handle = true;
-}
diff --git a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs
index d9897a1033f..71b7817a9c7 100644
--- a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs
@@ -2,7 +2,7 @@
 // This test relies on a specific interleaving that cannot be enforced
 // with just barriers. We must remove preemption so that the execution and the
 // error messages are deterministic.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 use std::ptr::addr_of_mut;
 use std::sync::{Arc, Barrier};
 use std::thread;
diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs
index f93cac8361e..c57cd7fcf0a 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs
@@ -43,11 +43,11 @@ unsafe fn read_second<T>(x: &mut T, y: *mut u8) {
 unsafe fn cell_protected_read() {
     print("[interior mut + protected] Foreign Read: Re* -> Frz");
     let base = &mut UnsafeCell::new(0u8);
-    name!(base.get(), "base");
+    name!(base as *mut _, "base");
     let alloc_id = alloc_id!(base.get());
     let x = &mut *(base as *mut UnsafeCell<u8>);
-    name!(x.get(), "x");
-    let y = (&mut *base).get();
+    name!(x as *mut _, "x");
+    let y = &mut *base as *mut UnsafeCell<u8> as *mut u8;
     name!(y);
     read_second(x, y); // Foreign Read for callee:x
     print_state!(alloc_id);
@@ -57,11 +57,11 @@ unsafe fn cell_protected_read() {
 unsafe fn cell_unprotected_read() {
     print("[interior mut] Foreign Read: Re* -> Re*");
     let base = &mut UnsafeCell::new(0u64);
-    name!(base.get(), "base");
+    name!(base as *mut _, "base");
     let alloc_id = alloc_id!(base.get());
     let x = &mut *(base as *mut UnsafeCell<_>);
-    name!(x.get(), "x");
-    let y = (&mut *base).get();
+    name!(x as *mut _, "x");
+    let y = &mut *base as *mut UnsafeCell<u64> as *mut u64;
     name!(y);
     let _val = *y; // Foreign Read for x
     print_state!(alloc_id);
@@ -72,11 +72,11 @@ unsafe fn cell_unprotected_read() {
 unsafe fn cell_unprotected_write() {
     print("[interior mut] Foreign Write: Re* -> Re*");
     let base = &mut UnsafeCell::new(0u64);
-    name!(base.get(), "base");
+    name!(base as *mut _, "base");
     let alloc_id = alloc_id!(base.get());
     let x = &mut *(base as *mut UnsafeCell<u64>);
-    name!(x.get(), "x");
-    let y = (&mut *base).get();
+    name!(x as *mut _, "x");
+    let y = &mut *base as *mut UnsafeCell<u64> as *mut u64;
     name!(y);
     *y = 1; // Foreign Write for x
     print_state!(alloc_id);
diff --git a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs
index 71e93d2f84f..840832c633c 100644
--- a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs
@@ -2,7 +2,7 @@
 // Note that we are *also* using barriers: the barriers enforce the
 // specific interleaving of operations that we want, but only the preemption
 // rate guarantees that the error message is also deterministic.
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-deterministic-concurrency
 //@compile-flags: -Zmiri-tree-borrows
 
 use std::sync::{Arc, Barrier};
diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
index b9d5ca06ed0..87eb447049d 100644
--- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
@@ -1,10 +1,10 @@
-//@revisions: default uniq
 //@compile-flags: -Zmiri-tree-borrows
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
 #![feature(allocator_api)]
 
 use std::{mem, ptr};
 
+// Test various tree-borrows-specific things
+// (i.e., these do not work the same under SB).
 fn main() {
     aliasing_read_only_mutable_refs();
     string_as_mut_ptr();
@@ -12,24 +12,6 @@ fn main() {
     direct_mut_to_const_raw();
     local_addr_of_mut();
     returned_mut_is_usable();
-
-    // Stacked Borrows tests
-    read_does_not_invalidate1();
-    read_does_not_invalidate2();
-    mut_raw_then_mut_shr();
-    mut_shr_then_mut_raw();
-    mut_raw_mut();
-    partially_invalidate_mut();
-    drop_after_sharing();
-    two_raw();
-    shr_and_raw();
-    disjoint_mutable_subborrows();
-    raw_ref_to_part();
-    array_casts();
-    mut_below_shr();
-    wide_raw_ptr_in_tuple();
-    not_unpin_not_protected();
-    write_does_not_invalidate_all_aliases();
 }
 
 #[allow(unused_assignments)]
@@ -111,96 +93,6 @@ fn returned_mut_is_usable() {
     *y = 1;
 }
 
-// ----- The tests below were taken from Stacked Borrows ----
-
-// Make sure that reading from an `&mut` does, like reborrowing to `&`,
-// NOT invalidate other reborrows.
-fn read_does_not_invalidate1() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let ret = unsafe { &(*xraw).1 };
-        let _val = x.1; // we just read, this does NOT invalidate the reborrows.
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-// Same as above, but this time we first create a raw, then read from `&mut`
-// and then freeze from the raw.
-fn read_does_not_invalidate2() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
-        let ret = unsafe { &(*xraw).1 };
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-
-// Escape a mut to raw, then share the same mut and use the share, then the raw.
-// That should work.
-fn mut_raw_then_mut_shr() {
-    let mut x = 2;
-    let xref = &mut x;
-    let xraw = &mut *xref as *mut _;
-    let xshr = &*xref;
-    assert_eq!(*xshr, 2);
-    unsafe {
-        *xraw = 4;
-    }
-    assert_eq!(x, 4);
-}
-
-// Create first a shared reference and then a raw pointer from a `&mut`
-// should permit mutation through that raw pointer.
-fn mut_shr_then_mut_raw() {
-    let xref = &mut 2;
-    let _xshr = &*xref;
-    let xraw = xref as *mut _;
-    unsafe {
-        *xraw = 3;
-    }
-    assert_eq!(*xref, 3);
-}
-
-// Ensure that if we derive from a mut a raw, and then from that a mut,
-// and then read through the original mut, that does not invalidate the raw.
-// This shows that the read-exception for `&mut` applies even if the `Shr` item
-// on the stack is not at the top.
-fn mut_raw_mut() {
-    let mut x = 2;
-    {
-        let xref1 = &mut x;
-        let xraw = xref1 as *mut _;
-        let _xref2 = unsafe { &mut *xraw };
-        let _val = *xref1;
-        unsafe {
-            *xraw = 4;
-        }
-        // we can now use both xraw and xref1, for reading
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs`
-    }
-    assert_eq!(x, 4);
-}
-
-fn partially_invalidate_mut() {
-    let data = &mut (0u8, 0u8);
-    let reborrow = &mut *data as *mut (u8, u8);
-    let shard = unsafe { &mut (*reborrow).0 };
-    data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
-    *shard += 1; // so we can still use `shard`.
-    assert_eq!(*data, (1, 1));
-}
-
-// Make sure that we can handle the situation where a location is frozen when being dropped.
-fn drop_after_sharing() {
-    let x = String::from("hello!");
-    let _len = x.len();
-}
-
 // Make sure that coercing &mut T to *const T produces a writeable pointer.
 fn direct_mut_to_const_raw() {
     let x = &mut 0;
@@ -210,150 +102,3 @@ fn direct_mut_to_const_raw() {
     }
     assert_eq!(*x, 1);
 }
-
-// Make sure that we can create two raw pointers from a mutable reference and use them both.
-fn two_raw() {
-    unsafe {
-        let x = &mut 0;
-        let y1 = x as *mut _;
-        let y2 = x as *mut _;
-        *y1 += 2;
-        *y2 += 1;
-    }
-}
-
-// Make sure that creating a *mut does not invalidate existing shared references.
-fn shr_and_raw() {
-    unsafe {
-        let x = &mut 0;
-        let y1: &i32 = mem::transmute(&*x); // launder lifetimes
-        let y2 = x as *mut _;
-        let _val = *y1;
-        *y2 += 1;
-    }
-}
-
-fn disjoint_mutable_subborrows() {
-    struct Foo {
-        a: String,
-        b: Vec<u32>,
-    }
-
-    unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
-        &mut (*this).a
-    }
-
-    unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
-        &mut (*this).b
-    }
-
-    let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };
-
-    let ptr = &mut foo as *mut Foo;
-
-    let a = unsafe { borrow_field_a(ptr) };
-    let b = unsafe { borrow_field_b(ptr) };
-    b.push(4);
-    a.push_str(" world");
-    assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#);
-}
-
-fn raw_ref_to_part() {
-    struct Part {
-        _lame: i32,
-    }
-
-    #[repr(C)]
-    struct Whole {
-        part: Part,
-        extra: i32,
-    }
-
-    let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
-    let whole = ptr::addr_of_mut!(*Box::leak(it));
-    let part = unsafe { ptr::addr_of_mut!((*whole).part) };
-    let typed = unsafe { &mut *(part as *mut Whole) };
-    assert!(typed.extra == 42);
-    drop(unsafe { Box::from_raw(whole) });
-}
-
-/// When casting an array reference to a raw element ptr, that should cover the whole array.
-fn array_casts() {
-    let mut x: [usize; 2] = [0, 0];
-    let p = &mut x as *mut usize;
-    unsafe {
-        *p.add(1) = 1;
-    }
-
-    let x: [usize; 2] = [0, 1];
-    let p = &x as *const usize;
-    assert_eq!(unsafe { *p.add(1) }, 1);
-}
-
-/// Transmuting &&i32 to &&mut i32 is fine.
-fn mut_below_shr() {
-    let x = 0;
-    let y = &x;
-    let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
-    let r = &**p;
-    let _val = *r;
-}
-
-fn wide_raw_ptr_in_tuple() {
-    let mut x: Box<dyn std::any::Any> = Box::new("ouch");
-    let r = &mut *x as *mut dyn std::any::Any;
-    // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
-    // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
-    // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
-    let pair = (r, &0);
-    let r = unsafe { &mut *pair.0 };
-    // Make sure the fn ptr part of the vtable is still fine.
-    r.type_id();
-}
-
-fn not_unpin_not_protected() {
-    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
-    // don't add protectors. (We could, but until we have a better idea for where we want to go with
-    // the self-referential-coroutine situation, it does not seem worth the potential trouble.)
-    use std::marker::PhantomPinned;
-
-    pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned);
-
-    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-        // `f` is allowed to deallocate `x`.
-        f(x)
-    }
-
-    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-        let raw = x as *mut _;
-        drop(unsafe { Box::from_raw(raw) });
-    });
-}
-
-fn write_does_not_invalidate_all_aliases() {
-    // In TB there are other ways to do that (`addr_of!(*x)` has the same tag as `x`),
-    // but let's still make sure this SB test keeps working.
-
-    mod other {
-        /// Some private memory to store stuff in.
-        static mut S: *mut i32 = 0 as *mut i32;
-
-        pub fn lib1(x: &&mut i32) {
-            unsafe {
-                S = (x as *const &mut i32).cast::<*mut i32>().read();
-            }
-        }
-
-        pub fn lib2() {
-            unsafe {
-                *S = 1337;
-            }
-        }
-    }
-
-    let x = &mut 0;
-    other::lib1(&x);
-    *x = 42; // a write to x -- invalidates other pointers?
-    other::lib2();
-    assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
-}
diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr
deleted file mode 100644
index 6098c855bde..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Res |      └─┬──<TAG=base>
-| Res |        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Act |      └─┬──<TAG=base>
-| Act |        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Act |      └─┬──<TAG=base>
-| Act |        └────<TAG=raw, uniq, uniq>
-──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.rs b/src/tools/miri/tests/pass/tree_borrows/unique.rs
deleted file mode 100644
index f1ca1b51aa8..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/unique.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-//@revisions: default uniq
-// We disable the GC for this test because it would change what is printed.
-//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
-
-#![feature(ptr_internals)]
-
-#[path = "../../utils/mod.rs"]
-#[macro_use]
-mod utils;
-
-use core::ptr::Unique;
-
-// Check general handling of Unique
-
-fn main() {
-    unsafe {
-        let base = &mut 5u8;
-        let alloc_id = alloc_id!(base);
-        name!(base);
-
-        let raw = &mut *base as *mut u8;
-        name!(raw);
-
-        // We create a `Unique` and expect it to have a fresh tag
-        // and uninitialized permissions.
-        let uniq = Unique::new_unchecked(raw);
-
-        // With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by
-        // `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual
-        // `base` pointer we care about we have to walk up the tree a bit.
-        //
-        // We care about naming this specific parent tag because it is the one
-        // that stays `Active` during the entire execution, unlike the leaves
-        // that will be invalidated the next time `as_ptr` is called.
-        //
-        // (We name it twice so that we have an indicator in the output of
-        // whether we got the distance correct:
-        // If the output shows
-        //
-        //    |- <XYZ: uniq>
-        //    '- <XYZ: uniq>
-        //
-        // then `nth_parent` is not big enough.
-        // The correct value for `nth_parent` should be the minimum
-        // integer for which the output shows
-        //
-        //    '- <XYZ: uniq, uniq>
-        // )
-        //
-        // Ultimately we want pointers obtained through independent
-        // calls of `as_ptr` to be able to alias, which will probably involve
-        // a new permission that allows aliasing when there is no protector.
-        let nth_parent = if cfg!(uniq) { 2 } else { 0 };
-        name!(uniq.as_ptr()=>nth_parent, "uniq");
-        name!(uniq.as_ptr()=>nth_parent, "uniq");
-        print_state!(alloc_id);
-
-        // We can activate the Unique and use it mutably.
-        *uniq.as_ptr() = 42;
-        print_state!(alloc_id);
-
-        // Write through the raw parent disables the Unique
-        *raw = 42;
-        print_state!(alloc_id);
-    }
-}
diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr
deleted file mode 100644
index 960c7e216e1..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Res |      └─┬──<TAG=base>
-| Res |        └─┬──<TAG=raw>
-|-----|          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Act |      └─┬──<TAG=base>
-| Act |        └─┬──<TAG=raw>
-| Act |          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────
-──────────────────────────────────────────────────
-Warning: this tree is indicative only. Some tags may have been hidden.
-0..   1
-| Act |    └─┬──<TAG=root of the allocation>
-| Act |      └─┬──<TAG=base>
-| Act |        └─┬──<TAG=raw>
-| Dis |          └────<TAG=uniq, uniq>
-──────────────────────────────────────────────────
diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
deleted file mode 100644
index af4c3b06931..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-//@revisions: default uniq
-// We disable the GC for this test because it would change what is printed.
-//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
-//@[uniq]compile-flags: -Zmiri-unique-is-unique
-
-#![feature(vec_into_raw_parts)]
-
-#[path = "../../utils/mod.rs"]
-#[macro_use]
-mod utils;
-
-// Check general handling of `Unique`:
-// there is no *explicit* `Unique` being used here, but there is one
-// hidden a few layers inside `Vec` that should be reflected in the tree structure.
-
-fn main() {
-    unsafe {
-        let base = vec![0u8, 1];
-        let alloc_id = alloc_id!(base.as_ptr());
-
-        // With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by
-        // `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual
-        // `base` pointer we care about we have to walk up the tree a bit.
-        //
-        // We care about naming this specific parent tag because it is the one
-        // that stays `Active` during the entire execution, unlike the leaves
-        // that will be invalidated the next time `as_ptr` is called.
-        //
-        // (We name it twice so that we have an indicator in the output of
-        // whether we got the distance correct:
-        // If the output shows
-        //
-        //    ├─ <TAG=base.as_ptr()>
-        //    └─ <TAG=base.as_ptr()>
-        //
-        // then `nth_parent` is not big enough.
-        // The correct value for `nth_parent` should be the minimum
-        // integer for which the output shows
-        //
-        //    └─ <TAG=base.as_ptr(), base.as_ptr(), ...>
-        // )
-        //
-        // Ultimately we want pointers obtained through independent
-        // calls of `as_ptr` to be able to alias, which will probably involve
-        // a new permission that allows aliasing when there is no protector.
-        let nth_parent = if cfg!(uniq) { 9 } else { 0 };
-        name!(base.as_ptr()=>nth_parent);
-        name!(base.as_ptr()=>nth_parent);
-
-        // Destruct the `Vec`
-        let (ptr, len, cap) = base.into_raw_parts();
-
-        // Expect this to be again the same pointer as the one obtained from `as_ptr`.
-        // Under `-Zmiri-unique-is-unique`, this will be a strict child.
-        name!(ptr, "raw_parts.0");
-
-        // This is where the presence of `Unique` has implications,
-        // because there will be a reborrow here iff the exclusivity of `Unique`
-        // is enforced.
-        let reconstructed = Vec::from_raw_parts(ptr, len, cap);
-
-        // The `as_ptr` here (twice for the same reason as above) return either
-        // the same pointer once more (default) or a strict child (uniq).
-        name!(reconstructed.as_ptr()=>nth_parent);
-        name!(reconstructed.as_ptr()=>nth_parent);
-
-        print_state!(alloc_id, false);
-    }
-}
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 4ab2bcb7f22..3e526813bb4 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -1,7 +1,6 @@
-//@revisions: stack tree tree_uniq
+//@revisions: stack tree
 //@compile-flags: -Zmiri-strict-provenance
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique
 #![feature(iter_advance_by, iter_next_chunk)]
 
 // Gather all references from a mutable iterator and make sure Miri notices if
diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs
index 9153c428e18..bdf57f281a0 100644
--- a/src/tools/miri/tests/pass/vecdeque.rs
+++ b/src/tools/miri/tests/pass/vecdeque.rs
@@ -1,8 +1,6 @@
-//@revisions: stack tree tree_uniq
+//@revisions: stack tree
 //@compile-flags: -Zmiri-strict-provenance
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique
-
 use std::collections::VecDeque;
 
 fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs
index 5d636431d86..eeab4ebf129 100644
--- a/src/tools/miri/tests/pass/weak_memory/weak.rs
+++ b/src/tools/miri/tests/pass/weak_memory/weak.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule
 
 // Tests showing weak memory behaviours are exhibited. All tests
 // return true when the desired behaviour is seen.
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index c37cf15d40a..46472b51f9c 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -44,8 +44,7 @@ pub fn flagsplit(flags: &str) -> Vec<String> {
 fn build_native_lib() -> PathBuf {
     let cc = env::var("CC").unwrap_or_else(|_| "cc".into());
     // Target directory that we can write to.
-    let so_target_dir =
-        Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-native-lib");
+    let so_target_dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("miri-native-lib");
     // Create the directory if it does not already exist.
     std::fs::create_dir_all(&so_target_dir)
         .expect("Failed to create directory for shared object file");
@@ -101,7 +100,7 @@ fn miri_config(
     let mut config = Config {
         target: Some(target.to_owned()),
         program,
-        out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri_ui"),
+        out_dir: PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("miri_ui"),
         threads: std::env::var("MIRI_TEST_THREADS")
             .ok()
             .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()),
@@ -319,10 +318,10 @@ fn main() -> Result<()> {
     let mut args = std::env::args_os();
 
     // Skip the program name and check whether this is a `./miri run-dep` invocation
-    if let Some(first) = args.nth(1) {
-        if first == "--miri-run-dep-mode" {
-            return run_dep_mode(target, args);
-        }
+    if let Some(first) = args.nth(1)
+        && first == "--miri-run-dep-mode"
+    {
+        return run_dep_mode(target, args);
     }
 
     ui(Mode::Pass, "tests/pass", &target, WithoutDependencies, tmpdir.path())?;
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index cea234cc74c..dfa884bc3f7 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "opt-dist"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 build_helper = { path = "../../build_helper" }
@@ -10,12 +10,11 @@ log = "0.4"
 anyhow = "1"
 humantime = "2"
 humansize = "2"
-sysinfo = { version = "0.31.2", default-features = false, features = ["disk"] }
+sysinfo = { version = "0.35.0", default-features = false, features = ["disk"] }
 fs_extra = "1"
 camino = "1"
 tar = "0.4"
 xz = { version = "0.1", package = "xz2" }
-serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 glob = "0.3"
 tempfile = "3.5"
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/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs
index 9342d164be4..946e926a3c0 100644
--- a/src/tools/opt-dist/src/environment.rs
+++ b/src/tools/opt-dist/src/environment.rs
@@ -26,6 +26,7 @@ pub struct Environment {
     use_bolt: bool,
     shared_llvm: bool,
     run_tests: bool,
+    fast_try_build: bool,
 }
 
 impl Environment {
@@ -106,6 +107,10 @@ impl Environment {
     pub fn run_tests(&self) -> bool {
         self.run_tests
     }
+
+    pub fn is_fast_try_build(&self) -> bool {
+        self.fast_try_build
+    }
 }
 
 /// What is the extension of binary executables on this platform?
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index deff69a7f9c..64ce5cc3775 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -113,13 +113,16 @@ impl Bootstrap {
             "library/std",
         ])
         .env("RUST_BACKTRACE", "full");
+        let cmd = add_shared_x_flags(env, cmd);
+
         Self { cmd, metrics_path }
     }
 
     pub fn dist(env: &Environment, dist_args: &[String]) -> Self {
         let metrics_path = env.build_root().join("build").join("metrics.json");
-        let cmd = cmd(&dist_args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>())
-            .env("RUST_BACKTRACE", "full");
+        let args = dist_args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>();
+        let cmd = cmd(&args).env("RUST_BACKTRACE", "full");
+        let cmd = add_shared_x_flags(env, cmd);
         Self { cmd, metrics_path }
     }
 
@@ -184,3 +187,7 @@ impl Bootstrap {
         Ok(())
     }
 }
+
+fn add_shared_x_flags(env: &Environment, cmd: CmdBuilder) -> CmdBuilder {
+    if env.is_fast_try_build() { cmd.arg("--set").arg("rust.deny-warnings=false") } else { cmd }
+}
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index d5e6640fb43..d2827ec01ca 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -95,7 +95,7 @@ enum EnvironmentCmd {
         #[arg(long)]
         benchmark_cargo_config: Vec<String>,
 
-        /// Perform tests after final build if it's not a try build
+        /// Perform tests after final build if it's not a fast try build
         #[arg(long)]
         run_tests: bool,
     },
@@ -111,11 +111,14 @@ enum EnvironmentCmd {
     },
 }
 
-fn is_try_build() -> bool {
+/// For a fast try build, we want to only build the bare minimum of components to get a
+/// working toolchain, and not run any tests.
+fn is_fast_try_build() -> bool {
     std::env::var("DIST_TRY_BUILD").unwrap_or_else(|_| "0".to_string()) != "0"
 }
 
 fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> {
+    let is_fast_try_build = is_fast_try_build();
     let (env, args) = match args.env {
         EnvironmentCmd::Local {
             target_triple,
@@ -144,6 +147,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .skipped_tests(skipped_tests)
                 .benchmark_cargo_config(benchmark_cargo_config)
                 .run_tests(run_tests)
+                .fast_try_build(is_fast_try_build)
                 .build()?;
 
             (env, shared.build_args)
@@ -167,6 +171,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .use_bolt(!is_aarch64)
                 .skipped_tests(vec![])
                 .run_tests(true)
+                .fast_try_build(is_fast_try_build)
                 .build()?;
 
             (env, shared.build_args)
@@ -187,6 +192,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .use_bolt(false)
                 .skipped_tests(vec![])
                 .run_tests(true)
+                .fast_try_build(is_fast_try_build)
                 .build()?;
 
             (env, shared.build_args)
@@ -350,9 +356,8 @@ fn execute_pipeline(
 
     // After dist has finished, run a subset of the test suite on the optimized artifacts to discover
     // possible regressions.
-    // The tests are not executed for try builds, which can be in various broken states, so we don't
-    // want to gatekeep them with tests.
-    if !is_try_build() && env.run_tests() {
+    // The tests are not executed for fast try builds, which can be broken and might not pass them.
+    if !is_fast_try_build() && env.run_tests() {
         timer.section("Run tests", |_| run_tests(env))?;
     }
 
@@ -361,7 +366,10 @@ fn execute_pipeline(
 
 fn main() -> anyhow::Result<()> {
     // Make sure that we get backtraces for easier debugging in CI
-    std::env::set_var("RUST_BACKTRACE", "1");
+    unsafe {
+        // SAFETY: we are the only thread running at this point
+        std::env::set_var("RUST_BACKTRACE", "1");
+    }
 
     env_logger::builder()
         .filter_level(LevelFilter::Info)
@@ -393,9 +401,9 @@ fn main() -> anyhow::Result<()> {
 
     let (env, mut build_args) = create_environment(args).context("Cannot create environment")?;
 
-    // Skip components that are not needed for try builds to speed them up
-    if is_try_build() {
-        log::info!("Skipping building of unimportant components for a try build");
+    // Skip components that are not needed for fast try builds to speed them up
+    if is_fast_try_build() {
+        log::info!("Skipping building of unimportant components for a fast try build");
         for target in [
             "rust-docs",
             "rustc-docs",
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 70a72bd1abe..b46ddd1d315 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -63,6 +63,12 @@ impl Command {
         }
     }
 
+    // Internal-only.
+    pub(crate) fn into_raw_command(mut self) -> std::process::Command {
+        self.drop_bomb.defuse();
+        self.cmd
+    }
+
     /// Specify a stdin input buffer. This is a convenience helper,
     pub fn stdin_buf<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
         self.stdin_buf = Some(input.as_ref().to_vec().into_boxed_slice());
diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs
index e91d101cb99..8da9f002c41 100644
--- a/src/tools/run-make-support/src/external_deps/cargo.rs
+++ b/src/tools/run-make-support/src/external_deps/cargo.rs
@@ -1,8 +1,11 @@
 use crate::command::Command;
 use crate::env_var;
+use crate::util::set_host_compiler_dylib_path;
 
 /// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest
 /// through the `CARGO` env var.
 pub fn cargo() -> Command {
-    Command::new(env_var("CARGO"))
+    let mut cmd = Command::new(env_var("CARGO"));
+    set_host_compiler_dylib_path(&mut cmd);
+    cmd
 }
diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs
index 433a57cd9fa..7040fb667cf 100644
--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
@@ -5,7 +5,7 @@ use crate::command::Command;
 use crate::env::env_var;
 use crate::util::set_host_compiler_dylib_path;
 
-/// Construct a new `rustdoc` invocation.
+/// Construct a new `rustdoc` invocation. This will configure the host compiler runtime libs.
 #[track_caller]
 pub fn rustdoc() -> Rustdoc {
     Rustdoc::new()
@@ -28,7 +28,7 @@ fn setup_common() -> Command {
 }
 
 impl Rustdoc {
-    /// Construct a bare `rustdoc` invocation.
+    /// Construct a bare `rustdoc` invocation. This will configure the host compiler runtime libs.
     #[track_caller]
     pub fn new() -> Self {
         let cmd = setup_common();
diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs
index 94955aefe57..9d5cc4e5876 100644
--- a/src/tools/run-make-support/src/macros.rs
+++ b/src/tools/run-make-support/src/macros.rs
@@ -28,6 +28,18 @@
 macro_rules! impl_common_helpers {
     ($wrapper: ident) => {
         impl $wrapper {
+            /// In very rare circumstances, you may need a e.g. `bare_rustc()` or `bare_rustdoc()`
+            /// with host runtime libs configured, but want the underlying raw
+            /// [`std::process::Command`] (e.g. for manipulating pipes or whatever). This function
+            /// will consume the command wrapper and extract the underlying
+            /// [`std::process::Command`].
+            ///
+            /// Caution: this will mean that you can no longer use the convenience methods on the
+            /// command wrapper. Use as a last resort.
+            pub fn into_raw_command(self) -> ::std::process::Command {
+                self.cmd.into_raw_command()
+            }
+
             /// Specify an environment variable.
             pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
             where
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 54f9dec9c7b..bd8146defae 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1750,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",
@@ -1762,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",
@@ -1781,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",
@@ -1792,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",
@@ -1803,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",
@@ -1813,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",
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/hir-def/src/expr_store/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
index 9ef03065651..d36e5205c73 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
@@ -224,7 +224,7 @@ impl ExprCollector<'_> {
 
                     curarg = parser.curarg;
 
-                    let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+                    let to_span = |inner_span: std::ops::Range<usize>| {
                         is_direct_literal.then(|| {
                             TextRange::new(
                                 inner_span.start.try_into().unwrap(),
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 2fd21bb0ed3..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
@@ -214,7 +214,7 @@ pub(crate) fn parse(
         };
     }
 
-    let to_span = |inner_span: parse::InnerSpan| {
+    let to_span = |inner_span: std::ops::Range<usize>| {
         is_source_literal.then(|| {
             TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
         })
@@ -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));
+                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-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 9a3c331ef32..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
@@ -301,6 +301,7 @@ impl<'db> MatchCheckCtx<'db> {
             // ignore this issue.
             Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
             Slice(_) => unimplemented!(),
+            DerefPattern(_) => unimplemented!(),
             &Str(void) => match void {},
             Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
             Never => PatKind::Never,
@@ -351,6 +352,7 @@ impl PatCx for MatchCheckCtx<'_> {
             },
             Ref => 1,
             Slice(..) => unimplemented!(),
+            DerefPattern(..) => unimplemented!(),
             Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
             | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited
             | Hidden | Missing | Wildcard => 0,
@@ -411,6 +413,7 @@ impl PatCx for MatchCheckCtx<'_> {
                 }
             },
             Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
+            DerefPattern(_) => unreachable!("Found a `DerefPattern` constructor in match checking"),
             Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
             | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited
             | Hidden | Missing | Wildcard => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 706d04484f6..f9ff3921266 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -5789,7 +5789,7 @@ The tracking issue for this feature is: [#120301]
 
 ------------------------
 
-Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`.
+Add the methods `from_days` and `from_weeks` to `Duration`.
 "##,
         default_severity: Severity::Allow,
         warn_since: None,
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 585e7ffb1ae..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,6 +179,18 @@ impl<'a> Converter<'a> {
                     COMMENT
                 }
 
+                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 {
+                        err = "invalid infostring for frontmatter"
+                    }
+                    FRONTMATTER
+                }
+
                 rustc_lexer::TokenKind::Whitespace => WHITESPACE,
 
                 rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE,
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index e6f93a1fbda..b1727509b13 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -150,6 +150,7 @@ pub enum SyntaxKind {
     STRING,
     COMMENT,
     ERROR,
+    FRONTMATTER,
     IDENT,
     LIFETIME_IDENT,
     NEWLINE,
@@ -483,6 +484,7 @@ impl SyntaxKind {
             | YIELD_EXPR
             | COMMENT
             | ERROR
+            | FRONTMATTER
             | IDENT
             | LIFETIME_IDENT
             | NEWLINE
@@ -994,7 +996,7 @@ impl SyntaxKind {
     }
 }
 #[macro_export]
-macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; [frontmatter] => { $ crate :: SyntaxKind :: FRONTMATTER } ; }
 impl ::core::marker::Copy for SyntaxKind {}
 impl ::core::clone::Clone for SyntaxKind {
     #[inline]
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 36cd675b9a6..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
@@ -173,7 +173,6 @@ fn test_fn_like_macro_clone_raw_ident() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn test_fn_like_fn_like_span_join() {
     assert_expand(
         "fn_like_span_join",
@@ -200,7 +199,6 @@ fn test_fn_like_fn_like_span_join() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn test_fn_like_fn_like_span_ops() {
     assert_expand(
         "fn_like_span_ops",
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index a0ae0d68581..10abca7d35d 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -133,6 +133,7 @@ Meta =
 
 SourceFile =
   '#shebang'?
+  '#frontmatter'?
   Attr*
   Item*
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 1243f6418fe..cd9f4dba890 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1525,6 +1525,10 @@ impl ast::HasDocComments for SourceFile {}
 impl ast::HasModuleItem for SourceFile {}
 impl SourceFile {
     #[inline]
+    pub fn frontmatter_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![frontmatter])
+    }
+    #[inline]
     pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
 }
 pub struct Static {
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/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
index 4b9c6edbe30..824b38fc872 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
@@ -670,6 +670,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
             [ident] => { $crate::SyntaxKind::IDENT };
             [string] => { $crate::SyntaxKind::STRING };
             [shebang] => { $crate::SyntaxKind::SHEBANG };
+            [frontmatter] => { $crate::SyntaxKind::FRONTMATTER };
         }
 
         impl ::core::marker::Copy for SyntaxKind {}
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index fb584103df5..0b389377011 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -19,13 +19,13 @@ dependencies = [
 
 [[package]]
 name = "ammonia"
-version = "4.0.0"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459"
+checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364"
 dependencies = [
+ "cssparser",
  "html5ever",
  "maplit",
- "once_cell",
  "tendril",
  "url",
 ]
@@ -97,9 +97,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.97"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "autocfg"
@@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "cc"
-version = "1.2.19"
+version = "1.2.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
+checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
 dependencies = [
  "shlex",
 ]
@@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.40"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -185,9 +185,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.36"
+version = "4.5.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
+checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.36"
+version = "4.5.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
+checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
 dependencies = [
  "anstream",
  "anstyle",
@@ -208,9 +208,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.47"
+version = "4.5.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
+checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1"
 dependencies = [
  "clap",
 ]
@@ -274,6 +274,29 @@ dependencies = [
 ]
 
 [[package]]
+name = "cssparser"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa"
+dependencies = [
+ "cssparser-macros",
+ "dtoa-short",
+ "itoa",
+ "phf",
+ "smallvec",
+]
+
+[[package]]
+name = "cssparser-macros"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "darling"
 version = "0.20.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -390,6 +413,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
 
 [[package]]
+name = "dtoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
+
+[[package]]
+name = "dtoa-short"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
+dependencies = [
+ "dtoa",
+]
+
+[[package]]
 name = "elasticlunr-rs"
 version = "3.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -509,9 +547,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
 dependencies = [
  "cfg-if",
  "libc",
@@ -537,9 +575,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.15.2"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
 
 [[package]]
 name = "heck"
@@ -555,16 +593,14 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
 [[package]]
 name = "html5ever"
-version = "0.27.0"
+version = "0.31.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
+checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c"
 dependencies = [
  "log",
  "mac",
  "markup5ever",
- "proc-macro2",
- "quote",
- "syn",
+ "match_token",
 ]
 
 [[package]]
@@ -608,21 +644,22 @@ dependencies = [
 
 [[package]]
 name = "icu_collections"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
 dependencies = [
  "displaydoc",
+ "potential_utf",
  "yoke",
  "zerofrom",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_locid"
-version = "1.5.0"
+name = "icu_locale_core"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -632,30 +669,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
-
-[[package]]
 name = "icu_normalizer"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
 dependencies = [
  "displaydoc",
  "icu_collections",
@@ -663,68 +680,55 @@ dependencies = [
  "icu_properties",
  "icu_provider",
  "smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
 
 [[package]]
 name = "icu_properties"
-version = "1.5.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
 dependencies = [
  "displaydoc",
  "icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
  "icu_properties_data",
  "icu_provider",
- "tinystr",
+ "potential_utf",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
+checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
 
 [[package]]
 name = "icu_provider"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
 dependencies = [
  "displaydoc",
- "icu_locid",
- "icu_provider_macros",
+ "icu_locale_core",
  "stable_deref_trait",
  "tinystr",
  "writeable",
  "yoke",
  "zerofrom",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
 name = "ident_case"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -743,9 +747,9 @@ dependencies = [
 
 [[package]]
 name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
 dependencies = [
  "icu_normalizer",
  "icu_properties",
@@ -775,9 +779,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
 name = "jiff"
-version = "0.2.6"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
+checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
 dependencies = [
  "jiff-static",
  "log",
@@ -788,9 +792,9 @@ dependencies = [
 
 [[package]]
 name = "jiff-static"
-version = "0.2.6"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
+checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -815,9 +819,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.171"
+version = "0.2.172"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "libdbus-sys"
@@ -846,9 +850,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
 
 [[package]]
 name = "litemap"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
 
 [[package]]
 name = "lock_api"
@@ -880,23 +884,31 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.12.1"
+version = "0.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
+checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a"
 dependencies = [
  "log",
- "phf",
- "phf_codegen",
- "string_cache",
- "string_cache_codegen",
  "tendril",
+ "web_atoms",
+]
+
+[[package]]
+name = "match_token"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
 name = "mdbook"
-version = "0.4.48"
+version = "0.4.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1"
+checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -971,7 +983,7 @@ dependencies = [
  "pulldown-cmark-to-cmark 19.0.1",
  "serde_json",
  "thiserror 1.0.69",
- "toml 0.8.20",
+ "toml 0.8.22",
 ]
 
 [[package]]
@@ -1154,6 +1166,7 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
 dependencies = [
+ "phf_macros",
  "phf_shared",
 ]
 
@@ -1178,6 +1191,19 @@ dependencies = [
 ]
 
 [[package]]
+name = "phf_macros"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "phf_shared"
 version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1217,6 +1243,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
 name = "precomputed-hash"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1224,9 +1259,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
@@ -1327,9 +1362,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.11"
+version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
+checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
 dependencies = [
  "bitflags 2.9.0",
 ]
@@ -1377,9 +1412,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "1.0.5"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
 dependencies = [
  "bitflags 2.9.0",
  "errno",
@@ -1464,9 +1499,9 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.10.8"
+version = "0.10.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -1530,9 +1565,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1541,9 +1576,9 @@ dependencies = [
 
 [[package]]
 name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1652,9 +1687,9 @@ dependencies = [
 
 [[package]]
 name = "tinystr"
-version = "0.7.6"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -1671,9 +1706,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.20"
+version = "0.8.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
+checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -1683,27 +1718,34 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.8"
+version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.22.24"
+version = "0.22.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
 dependencies = [
  "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
+ "toml_write",
  "winnow",
 ]
 
 [[package]]
+name = "toml_write"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
+
+[[package]]
 name = "topological-sort"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1757,12 +1799,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 
 [[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
-[[package]]
 name = "utf8_iter"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1858,6 +1894,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "web_atoms"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e"
+dependencies = [
+ "phf",
+ "phf_codegen",
+ "string_cache",
+ "string_cache_codegen",
+]
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2022,9 +2070,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.7.6"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
+checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
 dependencies = [
  "memchr",
 ]
@@ -2039,22 +2087,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "write16"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-
-[[package]]
 name = "writeable"
-version = "0.5.5"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
 
 [[package]]
 name = "yoke"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
 dependencies = [
  "serde",
  "stable_deref_trait",
@@ -2064,9 +2106,9 @@ dependencies = [
 
 [[package]]
 name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2096,10 +2138,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
 name = "zerovec"
-version = "0.10.4"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -2108,9 +2161,9 @@ dependencies = [
 
 [[package]]
 name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index a0b220c3557..10fde31306d 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.48"
+version = "0.4.49"
 default-features = false
 features = ["search"]
diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs
index 950e2fa478d..b9d08a0a295 100644
--- a/src/tools/rustdoc-gui-test/src/config.rs
+++ b/src/tools/rustdoc-gui-test/src/config.rs
@@ -20,8 +20,8 @@ pub(crate) struct Config {
 impl Config {
     pub(crate) fn from_args(args: Vec<String>) -> Self {
         let mut opts = Options::new();
-        opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH")
-            .reqopt("", "npm", "absolute path of npm", "PATH")
+        opts.optopt("", "nodejs", "absolute path of nodejs", "PATH")
+            .optopt("", "npm", "absolute path of npm", "PATH")
             .reqopt("", "out-dir", "output path of doc compilation", "PATH")
             .reqopt("", "rust-src", "root source of the rust source", "PATH")
             .reqopt(
@@ -47,9 +47,18 @@ impl Config {
             Err(f) => panic!("{:?}", f),
         };
 
+        let Some(nodejs) = matches.opt_str("nodejs").map(PathBuf::from) else {
+            eprintln!("`nodejs` was not provided. If not available, please install it");
+            std::process::exit(1);
+        };
+        let Some(npm) = matches.opt_str("npm").map(PathBuf::from) else {
+            eprintln!("`npm` was not provided. If not available, please install it");
+            std::process::exit(1);
+        };
+
         Self {
-            nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"),
-            npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"),
+            nodejs,
+            npm,
             rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(),
             out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(),
             initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(),
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 5c3be769f9e..e79b7803c60 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -63,6 +63,11 @@ impl Rewrite for ast::Local {
             return Err(RewriteError::SkipFormatting);
         }
 
+        // FIXME(super_let): Implement formatting
+        if self.super_.is_some() {
+            return Err(RewriteError::SkipFormatting);
+        }
+
         let attrs_str = self.attrs.rewrite_result(context, shape)?;
         let mut result = if attrs_str.is_empty() {
             "let ".to_owned()
diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs
index 58c8d21bd7a..1a9614bacec 100644
--- a/src/tools/rustfmt/src/parse/macros/asm.rs
+++ b/src/tools/rustfmt/src/parse/macros/asm.rs
@@ -1,10 +1,10 @@
 use rustc_ast::ast;
-use rustc_builtin_macros::asm::{AsmArgs, parse_asm_args};
+use rustc_builtin_macros::asm::{AsmArg, parse_asm_args};
 
 use crate::rewrite::RewriteContext;
 
 #[allow(dead_code)]
-pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> {
+pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<Vec<AsmArg>> {
     let ts = mac.args.tokens.clone();
     let mut parser = super::build_parser(context, ts);
     parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok()
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 3c3ebf556c5..9bb06c31c5c 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -175,6 +175,9 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
 
 const EXCEPTIONS_RUSTBOOK: ExceptionList = &[
     // tidy-alphabetical-start
+    ("cssparser", "MPL-2.0"),
+    ("cssparser-macros", "MPL-2.0"),
+    ("dtoa-short", "MPL-2.0"),
     ("mdbook", "MPL-2.0"),
     ("ryu", "Apache-2.0 OR BSL-1.0"),
     // tidy-alphabetical-end
@@ -426,10 +429,13 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "winapi-util",
     "winapi-x86_64-pc-windows-gnu",
     "windows",
+    "windows-collections",
     "windows-core",
+    "windows-future",
     "windows-implement",
     "windows-interface",
     "windows-link",
+    "windows-numerics",
     "windows-result",
     "windows-strings",
     "windows-sys",
@@ -459,7 +465,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "addr2line",
     "adler2",
-    "allocator-api2",
     "cc",
     "cfg-if",
     "compiler_builtins",
@@ -473,8 +478,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     "memchr",
     "miniz_oxide",
     "object",
-    "proc-macro2",
-    "quote",
     "r-efi",
     "r-efi-alloc",
     "rand",
@@ -483,8 +486,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     "rustc-demangle",
     "rustc-literal-escaper",
     "shlex",
-    "syn",
-    "unicode-ident",
     "unicode-width",
     "unwinding",
     "wasi",
@@ -498,8 +499,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     "windows_x86_64_gnu",
     "windows_x86_64_gnullvm",
     "windows_x86_64_msvc",
-    "zerocopy",
-    "zerocopy-derive",
     // tidy-alphabetical-end
 ];
 
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index e6b5aa59622..1d0ddd56eec 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -276,13 +276,7 @@ ui/auto-traits/issue-23080-2.rs
 ui/auto-traits/issue-23080.rs
 ui/auto-traits/issue-83857-ub.rs
 ui/auto-traits/issue-84075.rs
-ui/auxiliary/issue-13560-1.rs
-ui/auxiliary/issue-13560-2.rs
-ui/auxiliary/issue-13560-3.rs
 ui/auxiliary/issue-16822.rs
-ui/auxiliary/issue-18502.rs
-ui/auxiliary/issue-24106.rs
-ui/auxiliary/issue-76387.rs
 ui/bench/issue-32062.rs
 ui/binding/issue-40402-1.rs
 ui/binding/issue-40402-2.rs
@@ -1189,47 +1183,39 @@ ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs
 ui/impl-trait/in-trait/issue-102140.rs
 ui/impl-trait/in-trait/issue-102301.rs
 ui/impl-trait/in-trait/issue-102571.rs
-ui/impl-trait/issue-100075-2.rs
-ui/impl-trait/issue-100075.rs
-ui/impl-trait/issue-100187.rs
-ui/impl-trait/issue-102605.rs
-ui/impl-trait/issue-103181-1.rs
-ui/impl-trait/issue-103181-2.rs
-ui/impl-trait/issue-103599.rs
-ui/impl-trait/issue-108591.rs
-ui/impl-trait/issue-108592.rs
-ui/impl-trait/issue-35668.rs
-ui/impl-trait/issue-36792.rs
-ui/impl-trait/issue-46959.rs
-ui/impl-trait/issue-49556.rs
-ui/impl-trait/issue-49579.rs
-ui/impl-trait/issue-49685.rs
-ui/impl-trait/issue-51185.rs
-ui/impl-trait/issue-54966.rs
-ui/impl-trait/issue-55872-1.rs
-ui/impl-trait/issue-55872-2.rs
-ui/impl-trait/issue-55872-3.rs
-ui/impl-trait/issue-55872.rs
-ui/impl-trait/issue-56445.rs
-ui/impl-trait/issue-68532.rs
-ui/impl-trait/issue-72911.rs
-ui/impl-trait/issue-87450.rs
-ui/impl-trait/issue-99073-2.rs
-ui/impl-trait/issue-99073.rs
-ui/impl-trait/issue-99642-2.rs
-ui/impl-trait/issue-99642.rs
-ui/impl-trait/issue-99914.rs
+ui/impl-trait/issues/issue-100075-2.rs
+ui/impl-trait/issues/issue-100075.rs
+ui/impl-trait/issues/issue-100187.rs
+ui/impl-trait/issues/issue-102605.rs
+ui/impl-trait/issues/issue-103181-1.rs
+ui/impl-trait/issues/issue-103181-2.rs
+ui/impl-trait/issues/issue-103599.rs
 ui/impl-trait/issues/issue-104815.rs
 ui/impl-trait/issues/issue-105826.rs
+ui/impl-trait/issues/issue-108591.rs
+ui/impl-trait/issues/issue-108592.rs
 ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs
+ui/impl-trait/issues/issue-35668.rs
+ui/impl-trait/issues/issue-36792.rs
 ui/impl-trait/issues/issue-42479.rs
+ui/impl-trait/issues/issue-46959.rs
 ui/impl-trait/issues/issue-49376.rs
+ui/impl-trait/issues/issue-49556.rs
+ui/impl-trait/issues/issue-49579.rs
+ui/impl-trait/issues/issue-49685.rs
+ui/impl-trait/issues/issue-51185.rs
 ui/impl-trait/issues/issue-52128.rs
 ui/impl-trait/issues/issue-53457.rs
 ui/impl-trait/issues/issue-54600.rs
 ui/impl-trait/issues/issue-54840.rs
 ui/impl-trait/issues/issue-54895.rs
+ui/impl-trait/issues/issue-54966.rs
 ui/impl-trait/issues/issue-55608-captures-empty-region.rs
+ui/impl-trait/issues/issue-55872-1.rs
+ui/impl-trait/issues/issue-55872-2.rs
+ui/impl-trait/issues/issue-55872-3.rs
+ui/impl-trait/issues/issue-55872.rs
+ui/impl-trait/issues/issue-56445.rs
 ui/impl-trait/issues/issue-57464-unexpected-regions.rs
 ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
 ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -1239,8 +1225,10 @@ ui/impl-trait/issues/issue-58956.rs
 ui/impl-trait/issues/issue-62742.rs
 ui/impl-trait/issues/issue-65581.rs
 ui/impl-trait/issues/issue-67830.rs
+ui/impl-trait/issues/issue-68532.rs
 ui/impl-trait/issues/issue-70877.rs
 ui/impl-trait/issues/issue-70971.rs
+ui/impl-trait/issues/issue-72911.rs
 ui/impl-trait/issues/issue-74282.rs
 ui/impl-trait/issues/issue-77987.rs
 ui/impl-trait/issues/issue-78722-2.rs
@@ -1257,12 +1245,18 @@ ui/impl-trait/issues/issue-86719.rs
 ui/impl-trait/issues/issue-86800.rs
 ui/impl-trait/issues/issue-87295.rs
 ui/impl-trait/issues/issue-87340.rs
+ui/impl-trait/issues/issue-87450.rs
 ui/impl-trait/issues/issue-88236-2.rs
 ui/impl-trait/issues/issue-88236.rs
 ui/impl-trait/issues/issue-89312.rs
 ui/impl-trait/issues/issue-92305.rs
 ui/impl-trait/issues/issue-93788.rs
+ui/impl-trait/issues/issue-99073-2.rs
+ui/impl-trait/issues/issue-99073.rs
 ui/impl-trait/issues/issue-99348-impl-compatibility.rs
+ui/impl-trait/issues/issue-99642-2.rs
+ui/impl-trait/issues/issue-99642.rs
+ui/impl-trait/issues/issue-99914.rs
 ui/implied-bounds/issue-100690.rs
 ui/implied-bounds/issue-101951.rs
 ui/implied-bounds/issue-110161.rs
@@ -1378,12 +1372,8 @@ ui/intrinsics/issue-28575.rs
 ui/intrinsics/issue-84297-reifying-copy.rs
 ui/invalid/issue-114435-layout-type-err.rs
 ui/issue-11881.rs
-ui/issue-13560.rs
 ui/issue-15924.rs
 ui/issue-16822.rs
-ui/issue-18502.rs
-ui/issue-24106.rs
-ui/issue-76387-llvm-miscompile.rs
 ui/issues-71798.rs
 ui/issues/auxiliary/issue-11224.rs
 ui/issues/auxiliary/issue-11508.rs
@@ -2222,7 +2212,6 @@ ui/issues/issue-41479.rs
 ui/issues/issue-41498.rs
 ui/issues/issue-41549.rs
 ui/issues/issue-41604.rs
-ui/issues/issue-41628.rs
 ui/issues/issue-41652/auxiliary/issue-41652-b.rs
 ui/issues/issue-41652/issue-41652.rs
 ui/issues/issue-41677.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 44dd1e50f5b..8f9b07c49ac 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1624;
+const ISSUES_ENTRY_LIMIT: u32 = 1623;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/src/version b/src/version
index 59be592144c..636ea711ad9 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.88.0
+1.89.0